Seize the deal!
Caching Best Practices
Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly. Hypersistence Optimizer is that tool!
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, de default
FlushMode.AUTO is used which, as explained in this article, does not trigger a Persistence Context flush prior to executing a native SQL query.
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
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.
You can override the default
FlushMode either at the
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() );
FlushMode.ALWAYSmode instructs Hibernate to behave just like the JPA
FlushModeType.AUTOmode, 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.
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
If you enjoyed this article, I bet you are going to love my upcoming Online Workshops!
- Caching Best Practices with JPA and Hibernate (2.5 hours) on the 30th of September
- High-Performance SQL (4 hours) on the 6th of October in collaboration with Voxxed Days Ticino
- High-Performance SQL (12 hours) starting on the 28th of October in collaboration with Bouvet
FlushMode.ALWAYS strategy is desirable when bootstrapping Hibernate natively either via the Spring
SessionFactriyBuilder or the Hibernate
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.
Hypersistence Optimizer 2.2 has been released!