Logic performing several hundred queries takes significantly more time after migration from Hibernate 3

Solution Verified - Updated

Environment

  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 7
    • 6
  • Hibernate
    • 5
    • 4

Issue

  • Migrating from Hibernate 3 to Hibernate 4/5

  • Execution of several hundred queries within a transaction is significantly slower in Hibernate 4/5

  • High incidence in thread dumps of stack frames like the following

        ...
        at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:165)
        at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:156)
        at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
        at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:61)
        at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1166)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1223)
        at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
        ...
    

Resolution

When no pending changes relevant to the query exist1, use one of the following approaches:

Alternative strategies to speed up flush cycles include

NOTE documentation equivalent to the above for older Hibernate / JPA versions (e.g. Hibernate 4/JPA 2.0) exists but is not linked here.

1

WARNING: The application code MUST ensure that no pending changes relevant to the query exist. With either of the above approaches, explicit flush() may be used to ensure the database is in sync with any pending writes prior to operations which might ordinarily trigger implicit flush.
2: Content from javaee.github.io is not included.Entity manager flush mode | Content from docs.jboss.org is not included.Session flush mode

Root Cause

  • When executing transactional queries, pending changes (that have not yet been written to the database) must be flushed1
  • Failure to flush pending changes can result in incorrect query returns and/or overwrite of pending changes
  • Vulnerabilities where pre-query flush was not enforced in Hibernate 3 were addressed in Hibernate 4 as part of defect fixes
  • Cache scan (where there are hundreds or thousands of objects in the session cache) may impact execution time

Diagnostic Steps

  • Use the Byteman script below to trace flush calls

    RULE Session Flush
    CLASS org.hibernate.event.internal.AbstractFlushingEventListener
    METHOD prepareEntityFlushes(org.hibernate.event.spi.EventSource, org.hibernate.engine.spi.PersistenceContext)
    AT ENTRY
    BIND sess:Object = $1
    IF TRUE
    DO traceStack("Session hashCode: " +  sess.hashCode() + "\n" + "SessionImpl: " + $1 + "\n")
    ENDRULE
    
  • Enable Hibernate SQL trace to correlate the above with query execution

Components
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.