Hibernate Session doWork and doReturningWork methods
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, I’m going to explain how the Hibernate Session
doWork
and doReturningWork
methods work, and when you should use them.
Hibernate Session doWork
The Hibernate Session
provides a doWork
method that has the following signature:
void doWork(Work work) throws HibernateException;
And the Work
interface is defined as follows:
public interface Work { void execute(Connection connection) throws SQLException; }
So, the doWork
method allows us to get access to the underlying JDBC Connection
that’s enlisted in the current local (JDBC) or global (JTA) transaction.
Normally, you don’t need to use the JDBC Connection
object to execute SELECT, INSERT, UPDATE, or DELETE statements with JPA and Hibernate, since you can use the JPA Query
API for that.
However, there are several JDBC features that can only be enabled via the Connection
object, like setting a global statement timeout threshold via the setNetworkTimeout
method.
Assuming that we created the following Java Executor
:
private Executor executor = Executors.newFixedThreadPool(connectionPoolSize);
We can now set the global statement timeout to the value of 1000 milliseconds, like this:
Session session = entityManager.unwrap(Session.class); session.doWork(connection -> { connection.setNetworkTimeout( executor, (int) TimeUnit.SECONDS.toMillis(1) ); });
Notice that since the Work
interface is a @FunctionalInterface
, we can pass a Java lambda to the doWork
method call.
So, now, if an SQL statement takes more than 1 second, it will fail with a SocketTimeoutException
:
try { entityManager.createNativeQuery( "select pg_sleep(2)" ) .getResultList(); } catch (Exception e) { assertTrue( SocketTimeoutException.class.isInstance( ExceptionUtil.rootCause(e) ) ); }
Hibernate Session doReturningWork
The Hibernate Session
also provides a doReturningWork
method that has the following signature:
<T> T doReturningWork(ReturningWork<T> work) throws HibernateException;
And the ReturningWork
interface is defined as follows:
public interface ReturningWork<T> { public T execute(Connection connection) throws SQLException; }
So, unlike the doWork
method, the doReturningWork
allows us to return an object to the method caller.
For example, we can use the doReturningWork
method to get the current transaction isolation level:
Session session = entityManager.unwrap(Session.class); int isolationLevel = session.doReturningWork( connection -> connection.getTransactionIsolation() ); assertEquals( Connection.TRANSACTION_READ_COMMITTED, isolationLevel );
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
While most of the time, you can use the JPA or Hibernate-specific API to execute SQL statements or call database procedures or functions, the doWork
and doReturningWork
Hibernate Session
methods give access to the underlying JDBC Connection
, therefore, allowing us to execute any operation that is possible using the JDBC API.
