Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA: caching queries

I'm using JPA to load and persist entities in my Java EE-based web application. Hibernate is used as an implementation of JPA, but I don't use Hibernate-specific features and only work with pure JPA.

Here is some DAO class, notice getOrders method:

class OrderDao {
  EntityManager em;

  List getOrders(Long customerId) {
    Query q = em.createQuery(
      "SELECT o FROM Order o WHERE o.customerId = :customerId");
    q.setParameter("customerId", customerId);
    return q.getResultList();
  }
}

Method is pretty simple but it has a big drawback. Each time the method is called following actions are performed somewhere within JPA implementation:

  1. JPQL expression is parsed and compiled to SQL.
  2. Either Statement or PreparedStatement instance is created and initialized.
  3. Statement instance is filled with parameters and executed.

I believe that steps 1 and 2 of above should be implemented once per application lifetime. But how to make it? In other words, I need that Query instances to be cached.

Of course I can implement such a cache on my side. But wait, I am using modern powerful ORM's! Didn't they already made this for me?

Notice that I'm not mentioning something like Hibernate query cache which caches result of queries. Here I'd like to execute my queries a bit more quickly.

like image 967
Andrey Avatar asked Aug 26 '10 19:08

Andrey


People also ask

Does JPA cache query results?

Query results are not cached. By default, the query will cache 100 query results (see query-results-cache. size); if the same named query with the same arguments is re-executed EclipseLink will skip the database and return the cached results.

Does JPA have cache?

Caching in JPA is required within a transaction or within an extended persistence context to preserve object identity, but JPA does not require that caching be supported across transactions or persistence contexts. JPA 2.0 defines the concept of a shared cache.

How does JPA caching work?

An application that uses JPA reads an entity either explicitly (by executing a find or a query) or implicitly (by navigating to a related entity). To guarantee referential consistency, JPA first tries to locate an entity in the persistence context associated with the entity manager.


2 Answers

Use statically defined named queries. They are more efficient because the JPA persistence provider can translate the JP QL string to SQL once at application startup time, as opposed to every time the query is executed, and are recommended in particular for queries that are executed frequently.

A named query is defined using the @NamedQuery annotation that is typically used on the entity class of the result. In your case, on the Order entity:

@Entity
@NamedQueries({
    @NamedQuery(name="Order.findAll",
                query="SELECT o FROM Order o"),
    @NamedQuery(name="Order.findByPrimaryKey",
                query="SELECT o FROM Order o WHERE o.id = :id"),
    @NamedQuery(name="Order.findByCustomerId",
                query="SELECT o FROM Order o WHERE o.customerId = :customerId")
})
public class Order implements Serializable {
    ...
}

It is also recommended to prefix named queries with the entity name (to have some kind of name space and avoid collisions).

And then in the DAO:

class OrderDao {
    EntityManager em;

    List getOrders(Long customerId) {
        return em.createNamedQuery("Order.findByCustomerId")
                 .setParameter("customerId", customerId);
                 .getResultList();
    }
}

PS: I reused the query you suggested as example but it's somehow weird to have the customerId on the Order, I would expect a Customer instead.

References

  • JPA 1.0 Specification
    • Section 3.6.4 "Named Queries"
like image 161
Pascal Thivent Avatar answered Sep 29 '22 11:09

Pascal Thivent


The is a query plan cache in Hibernate. So the HQL is not parsed every time the DAO is called (so #1 really occurs only once in your application life-time). It's QueryPlanCache. It's not heavily documented, as it "just works". But you can find more info here.

like image 31
Thierry-Dimitri Roy Avatar answered Sep 29 '22 11:09

Thierry-Dimitri Roy