… rather than just a synchronization. Otherwise, at least SharedEntityManagerCreator will create a 'lingering' EM inside NEVER/NOT_SUPPORTED propagation, which is closed only after exiting from inside that boundary.
I did look at some other usage of isSynchronizationActive, and I'm not sure if it is more proper to use isActualTransactionActive there. I suspect this might be true for a couple of places.
isActualTransactionActive and doGetTransactionalEntityManager seem to be around here since before the recorded history, so we can't say if isActualTransactionActive was added after or before doGetTransactionalEntityManager.
Edit of #29430, which I messed up by pushing to main in my repository.
Comment From: jhoeller
Sorry for noticing your original issue before: It's not just about actual transactions, that code is about reusing an EntityManager
for a given boundary intentionally. As long as we have a managed boundary there, we'll expose the same EntityManager
instance within that scope, reusing its first-level cache. This has been the case ever since the inception of Spring's JPA support. So it works by design, accepting a longer-open EntityManager
handle for reuse within the scope.
While it is true that such resource handles may 'linger' when a transaction gets suspended, such a scenario is usually not good practice to begin with. The common suspension scenarios have REQUIRED
(potentially with readOnly=true
) in combination with REQUIRES_NEW
, whereas SUPPORTS
is mostly used on its own for read-only scenarios where no actual transaction is desired. NOT_SUPPORTED
and NEVER
are mostly there for completeness (aligned with EJB), we rarely see those in practice.
An open EntityManager
does not necessarily mean a bound JDBC Connection
. In case of longer-lived EntityManager
instances, the connection release mode in the persistence provider can be configured accordingly, aggressively releasing each obtained Connection
back to the pool after every operation. With such a setup, the EntityManager
is quite literally just a first-level cache for a particular processing step in the application, occupying some memory but not holding any resources.
Last but not least, synchronization can be turned off on the transaction manager. JpaTransactionManager
will then only manage an actual transactional EntityManager
for each required boundary (pre-exposed by JpaTransactionManager
for each transaction rather than lazily obtained through doGetTransactionalEntityManager
), not accepting any other scoped resources.