How to override the default Hibernate Session FlushMode
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.
So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!
Introduction
In this article, we are going to see how we can override the default FlushMode used by Hibernate.
If you bootstrap Hibernate natively, and not as a JPA provider, the default Hibernate FlushMode.AUTO
strategy will be used, which, as explained in this article, does not trigger a Persistence Context flush prior to executing a native SQL query.
How to override the default Hibernate Session FlushMode@vlad_mihalcea https://t.co/7II0qm0eDv pic.twitter.com/eAijTH25l0
— Java (@java) July 18, 2019
Hibernate default FlushMode AUTO
Assuming we have no Post
entity in our database:
assertEquals( 0, ((Number) entityManager .createQuery( "select count(p) " + "from Post p") .getSingleResult() ).intValue() );
If we persist a Post
entity:
entityManager .persist( new Post() .setTitle( "High-Performance Java Persistence" ) );
and we bootstrap Hibernate natively using the SessionFactoryBuilder
, then the default FlushMode.AUTO
will not trigger a Persistence Context flush when a native SQL query is executed:
assertEquals( 0, ((Number) entityManager .createNativeQuery( "select count(*) " + "from post") .getSingleResult() ).intValue() );
This behavior only happens if Hibernate is bootstrap using the SessionFactory
class. We can see that flush is delayed until the Hibernate transaction is about to commit:
CALL NEXT VALUE FOR hibernate_sequence SELECT COUNT(*) FROM post -- o.h.e.t.i.TransactionImpl - committing INSERT INTO post ( title, id ) VALUES ( 'High-Performance Java Persistence', 1 )
When using JPA, the Persistence Context is flushed on every query execution, be it JPQL, Criteria API or a native SQL query.
How to manually override the default Hibernate Session FlushMode
You can override the default FlushMode
either at the Query
or Session
level.
If you are only interested in changing the FlushMode
only for the duration of the currently executing query, then you can do that as illustrated in the following example:
assertEquals( 1, ((Number) entityManager .createNativeQuery( "select count(*) " + "from post" ) .unwrap(org.hibernate.query.Query.class) .setHibernateFlushMode(FlushMode.ALWAYS) .getSingleResult() ).intValue() );
The
FlushMode.ALWAYS
mode instructs Hibernate to behave just like the JPAFlushModeType.AUTO
mode, therefore, triggering a Persistence Context flush prior to any query, be it JPQL, Criteria API or a native SQL query.
If you want to override the FlushMode
for every query executed by the current Hibernate Session
, then you can change the FlushMode
as follows:
entityManager .unwrap(Session.class) .setHibernateFlushMode(FlushMode.ALWAYS);
However, this would require you to manually set the FlushMode.ALWAYS
for every Session
, which is not very convenient for the application developer.
How to automatically override the default Hibernate Session FlushMode
You can define a specific FlushMode
at the Hibernate configuration level using the org.hibernate.flushMode
configuration property:
<property name="org.hibernate.flushMode" value="ALWAYS" />
This way, every Session
will use the ALWAYS
flush strategy, so we don’t need to manually override the default AUTO
flush mode at the Query
or Session
level.
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
Setting the FlushMode.ALWAYS
strategy is desirable when bootstrapping Hibernate natively either via the Spring LocalSessionFactoryBean
or the Hibernate BootstrapServiceRegistryBuilder
.
This way, you provide read-your-writes consistency guarantee, and native SQL queries will include any pending modifications that were scheduled to be executed at flush time.
