What happens when committing a transaction from the entity manager that doesn't contain any dirty object? Can it be that no COMMIT command is sent to the DB?
I was having some test cases failing now and then without a reasonable cause. After some investigation, I have now a theory which I would like to have confirmed here.
I have a small fixture framework to prepare the data on the DB for each test. The fixtures use such a method to store objects to the DB using JPA (Hibernate):
public <R> R doInTransaction(final Function<EntityManager, R> whatToDo) {
final EntityManager em = emf.createEntityManager();
final R result;
try {
try {
em.getTransaction().begin();
result = whatToDo.apply(em);
em.getTransaction().commit();
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
} finally {
em.close();
}
return result;
}
So, the fixture calls this method passing the whatToDo function where objects are persisted and the method wraps a transaction around the passed function. My failing test cases are using a fixture that relies on legacy code that uses stored procedures and store the objects directly via JDBC, i. e. instead of using em.persist()
, I use the following in the passed function to call the stored procedures:
em.unwrap(Session.class).doWork(connection -> {
// stored procedures are called here directly over JDBC
});
So, my theory is that JPA on this circumstance is not immediately committing as there are no JPA dirty objects managed by the EntityManager. Consequently, the actual commits occurs only later, i. e. after the assertion of my test and the test fails. Could it be?
What is the transactional behaviour of Hibernate when "unwrapping" the connection out of the EntityManager?
I've added now an em.flush()
before the em.getTransaction().commit()
and it seems to help, but I'm still not 100% confident that this solves the issue. Can somebody confirm?