user1241043
user1241043

Reputation: 1

Tomcat, Hibernate, JPA and Flushing

I have a simple project that I'm using to learn Hibernate and JPA. I've got the project set up and working, able to persist() data in the (HSQLDB) database, and createQuery() data back out.

I enabled the show_sql option in persistence.xml to see what was happening underneath. I'm confused as to why every time i query the data a SQL query is run, even when no other transaction/commit has been executed.

I'm using a single EntityManager created via Persistence.createEntityManagerFactory() in a method of a class, called by my Servlet. When this is created I call em.setFlushMode(FlushModeType.COMMIT).

public class ThingPersist {
private static EntityManagerFactory emf;
private static EntityManager em;
public static EntityManager getEntityManager()
{
    if (emf == null)
        emf = Persistence.createEntityManagerFactory("thingPersist");
    if (em == null)
    {   
        em = emf.createEntityManager();
        em.setFlushMode(FlushModeType.COMMIT);
    }
    return em;
}
}

The doGet() method of my Servlet queries the data (the Thing class has hashCode() and equals() overrides):

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    EntityManager em = ThingPersist.getEntityManager();
    em.setFlushMode(FlushModeType.COMMIT);
    List<Thing> things = em.createQuery("from Thing", Thing.class).getResultList();
    for (Thing thing : things)
        response.getWriter().println(thing.getSomeString());
}

Hibernate then shows the following SQL:

Hibernate: 
select
    thing0_.id as id0_,
    thing0_.someString as someString0_ 
from
    Thing thing0_

If I call the servlet again, the same SQL is executed. If I put another identical createQuery() block immediately after, Hibernate reports the same SQL executed twice for each doGet().

Why is Hibernate querying the database on each call? Shouldn't the EntityManager be caching the Thing object (until a commit() changes it)?

Thanks for any help!

Upvotes: 0

Views: 548

Answers (1)

JB Nizet
JB Nizet

Reputation: 691933

The flush mode indicates when changes done to entities in the session must be written to the database. It has nothing to do with queries.

Moreover, you're not starting any transaction in your code.

And finally, even if you were, when you execute a query, Hibernate executes this query. The only calls that would not trigger a query the second time are em.find() and em.getReference(). The reasons are that

  • the lifetime of the first-level cache is typically very short (the duration of a transaction), and it's thus pretty rare to execute the same query twice in the same transaction.
  • depending on the isolation level, the query might return different results between two calls, because another transaction might have made changes between the two queries.

Upvotes: 1

Related Questions