JPA: caching queries

前端 未结 6 1592
心在旅途
心在旅途 2021-02-07 08:13

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

6条回答
  •  别那么骄傲
    2021-02-07 09:12

    JPA 2.1, section "3.1.1 EntityManager Interface":

    The Query, TypedQuery, StoredProcedureQuery, CriteriaBuilder, Metamodel, and EntityTransaction objects obtained from an entity manager are valid while that entity manager is open.

    The lesson to take home from this quote is that the enlisted query types can only be cached for as long as the entity manager remains open - which we have no saying about for container-managed entity managers.

    Three solutions come to mind. 1) Named queries as others have pointed out. 2) Cache a CriteriaQuery instead and hopefully the provider can toss in some kind of optimizations out of it. 3) Use an application-managed entity manager (that remains open).

    Cache a CriteriaQuery

    @Stateless
    public class OrderRepository
    {
        @PersistenceUnit
        EntityManagerFactory emf;
    
        @PersistenceContext
        EntityManager em;
    
        private CriteriaQuery query;
    
        private Parameter param;
    
        @PostConstruct
        private void constructQuery() {
            CriteriaBuilder b = emf.getCriteriaBuilder();
            query = b.createQuery(Order.class);
            param = b.parameter(long.class);
            ...
        }
    
        public List findByCustomerKey(long key) {
            return em.createQuery(query)
                     .setParameter(param, key)
                     .getResultList();
        }
    }
    

    Use an application-managed entity manager

    @Stateless
    public class OrderRepository
    {
        @PersistenceUnit
        EntityManagerFactory emf;
    
        private EntityManager em;
    
        private TypedQuery query;
    
        @PostConstruct
        private void initialize() {
            em = emf.createEntityManager();
            query = em.createQuery("SELECT o FROM Order o WHERE o.id = ?1", Order.class);
        }
    
        public List findByCustomerKey(long key) {
            try {
                return query.setParameter(1, key)
                            .getResultList();
            }
            finally {
                em.clear(); // returned entities are detached
            }
        }
    
        @PreDestroy
        private void closeEntityManager() {
            em.close();
        }
    }
    

提交回复
热议问题