Spring - Hibernate improve transaction performance with FlushMode

I'm trying to improve the performances of my asynk transactional method.

In this task I have to read almost 7500 record from a table, elaborate it, and insert/update a corresponding row in another table.

I'm using spring data jpa with hibernate.

In order to get a ScrollableResults I inject the EntityManager into my service.

Here how I get my ScrollableResult object:

Session session = (Session) em.unwrap(Session.class);
        ScrollableResults res = session.createQuery("from SourceTable s")
                .setCacheMode(CacheMode.IGNORE)
                .scroll(ScrollMode.FORWARD_ONLY);


while (res.next()){
.... // em.flush() called every 40 cycles
}

Cycling on result take about 60 seconds.

And here the bottleneck. If inside my loop I execute a simple query:

query = em.createQuery("from DestTable d where d.item.id = :id", DestTable.class);

 while (res.next()){
     query.setParameter("id", myId).getSingleResult();     
 }

The execution time become x10 slower.. and takes about 600s.

I've tried to modify a parameter of my Session or of my EntityManager: session.setFlushMode(FlushModeType.COMMIT); em.setFlushMode(FlushModeType.COMMIT);

It increase the performance and removing the manual flush() method the work is done in 40s!!!

So my questions are:

  • What is the difference of call setFlushMode on session or on enityManager?
  • Why setFlushMode(FlushModeType.COMMIT); increase in that way performance, and I cannot have same performance only by manually flushing entityManager?

Answers


The problem is that the default flush mode is FlushModeType.AUTO. In auto flush mode, Hibernate will flush before each query (only queries, not find operations). This means that in your above example, by default, Hibernate is flushing each time you call getSingleResult(). The reason it does this is because it's possible that the changes you have made would affect the results of your query and so Hibernate wants your query to be as accurate as possible and flushes first.

You don't see the performance hit in your first example because you are only issuing one query and scrolling through it. The best solution I have found is the one you mentioned which is just to set the flush mode to COMMIT. There should be no difference between calling setFlushMode on the Session or the EntityManager.


Need Your Help

Java Adding string to a string array

java arrays string

Hello I have been trying to add a String to a String[]. Here is what I have,