Logic performing several hundred queries takes significantly more time after migration from Hibernate 3
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:
- Change the default Content from javaee.github.io is not included.query flush mode (
AUTO) toCOMMIT - Temporarily change the session flush mode2 to
COMMITfor a subset of the application logic - To reduce the impact of updates (minimizing impact on session cache size), consider Hibernate options for batch processing
Alternative strategies to speed up flush cycles include
- Use of Content from docs.jboss.org is not included.read only entities which Hibernate does not dirty-check during flush
- Implementation of an Content from docs.jboss.org is not included.interceptor where the Content from docs.jboss.org is not included.findDirty() event hook performs application-specific logic to identify dirty properties
NOTE documentation equivalent to the above for older Hibernate / JPA versions (e.g. Hibernate 4/JPA 2.0) exists but is not linked here.
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
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.