1

I like to use the DAO pattern and have a class which do all my SQL request for a particular table and JPA entity. I have for example something like:

public class MyDao {

    @PersistenceContext(name = "mycontext")
    private EntityManager entityManager;

    public List<MyEntity> find(String code)  {

        return getEntityManager()
            .createQuery("FROM MyEntity e WHERE e.code = :code")
            .setParameter("code", code)
            .getResultList();

    }

}

But I also know we can use named query directly on the entity class with a static method (I don't like this way):

@Entity
@Table
@NamedQueries({
    @NamedQuery(name = "find", query = "FROM MyEntity e WHERE e.code = :code")
})
public class MyEntity {

    ...

    public static List<MyEntity> find(EntityManager entityManager, String code) {

        return entityManager.createNamedQuery("find", MyEntity.class)
            .setParameter("code", code)
            .getResultList();

    }

}

Is one of those method better than the other one ? If I want to execute the same SQL query thousands of times in the same transaction, is both methods keep in JPA memory (or somewhere else) the prepared statement ? Which seems to be a good practise in this case. I would think the second method does it because it's static but not the first one. Am I wrong ?

cheb1k4
  • 2,316
  • 7
  • 26
  • 39
  • JPQL starts "SELECT {alias}". That part is not optional. It is for the JPA implementation to define the most efficient way of handling its internals, not for the user – Neil Stockton Feb 08 '16 at 18:15

1 Answers1

2

The advantage for declaritively defined queries via @NamedQuery is that they will be precompiled, can be cached within the secondary cache and syntactically validated on startup if you enable it within the persistence.xml using the JPA non-hibernate specific API.

So if you plan on executing a query, using only JPA, often it is probably best to use NamedQuery and cache the query.

So for JPA using hibernate you could do something like this:

            @NamedQuery(name="AbstractBaseQuestion.findAllInstancesByGroupID", query="SELECT q FROM AbstractBaseQuestion q WHERE q.isTemplate = FALSE", hints={@QueryHint(name="org.hibernate.cacheable", value="true"),@QueryHint(name="org.hibernate.cacheMode", value="NORMAL"),}),

Within your persistence.xml for hibernate you can validate these @NamedQueries on startup:

      <property name="hibernate.hbm2ddl.auto" value="validate"/>

Now the first method you suggested can be cached and precompiled if you use the Hibernate Session API. I imagine there are equivalents on EclipseLink and other ORM's but at this point you are using non-JPA features which could make moving from one JPA implementation to another difficult.

If you don't do that extra implementation specific work your query is going to not be cached and you will pay a performance penalty.

I hope that helps.

sagneta
  • 1,546
  • 18
  • 26