We have an interesting case in some production code: inside a method annotated with transactional some operation takes much longer than expected, and our database connection pool closes the database connection.
A query inside the method then throws an exception ("Connection has already been closed").
The JpaLocalTxnInterceptor takes care of starting a unit of work (we don't manage it ourselves in this instance). I would expect the unit of work to have ended after the method call.
However, this is what happens:
- rollbackIfNecessary is called, which tries to execute a transaction rollback
- the rollback throws an exception ("Connection has already been closed")
- as the transaction is still seen as active, the unit of work is not closed (line 82 in JpaLocalTxnInterceptor)
- every next call to the annotated method tries to reuse the unit of work and fails
The above can be circumvented by managing the unit of work ourselves. But that means that we cannot rely on the "it just works"-behavior of the transactional annotation, which is a shame.
It also means more boilerplate code in every location where we now rely on the transactional annotation to do the work for us.
Ideally the interceptor should end the unit of work, even when it cannot perform a rollback.