I have a question about how Spring Data repositories are handling the datasource connections. Assuming Spring Data repositories open and close the connection and the connection when the method executes, how does the transaction started by declaring @Transactional
in my service layer span across multiple repository calls?
Who handles the database connections? The @Transactional
annotation or the JPA repository?
Ultimately it's the Spring JPA / Transaction infrastructure managing the connection via the thead-bound management of EntityManager
instances. The scope of the transaction is controlled by @Transactional
annotations in the user code but ultimately defaulted in Spring Data JPA's repository implementation. Connection acquisition is performed eagerly in case an OpenEntityManagerInViewFilter
is used (enabled by default in Spring Boot 1.x and 2.x).
SimpleJpaRepository
is equipped with Spring's @Transactional
annotations so that it will make sure it runs transactions in cases JPA requires them (e.g. to execute a call to EntityManager.persist(…)
or ….merge(…)
). Their default configuration makes sure, they automatically take part in transactions started at higher levels of abstraction. I.e. if you have a Spring component that's @Transactional
itself, repositories will simply participate in the already running transaction:
@Component
class MyService {
private final FirstRepository first;
private final SecondRepository second;
// Constructor omitted for brevity
@Transactional
void someMethod() {
… = first.save(…);
… = second.save(…);
}
}
Both repositories participate in the transaction and a failure in one of them will roll back the entire transaction.
To achieve that, the JpaTransactionManager
will use the transaction management API exposed by JPA's EntityManager
to start a transaction and acquire a connection for the lifetime of the EntityManager
instance. See JpaTransactionManager.doBegin(…)
for details.
OpenEntityManagerInViewFilter
or –Interceptor
Unless explicitly deactivated, Spring Boot 1.x and 2.x web applications run with an OpenEntityManagerInViewFilter
deployed. Its used to create an EntityManager
and thus acquire a connection pretty early and keep it around until very late in the request processing, namely after the view has been rendered. This has the effect of JPA lazy-loading being available to the view rendering but keeps the connection open for longer than if it was only needed for the actual transactional work.
That topic is quite a controversial one as its a tricky balance between developer convenience (the ability to traverse object relations to loaded lazily in the view rendering phase) at the risk of exactly that triggering expensive additional queries and keeping the resources in use for a longer time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With