This directly relates to this other question, as a natural follow-up question (which was asked in comments, but was never replied to).
Textual description
Assuming:
- the application uses the default
REQUIRED
transactional propagation - the application uses the
DEFAULT
transactional isolation - the database's transactional isolation defaults to
READ_COMMITTED
(e.g. Postgres)
Two operations exist in separate classes:
- Read some entries
- Read some entries + Update them
Now assume that:
- the second operation calls the first one to fulfill the "Read some entries" part
- the second operation's method is marked with
@Transactional(isolation=Isolation.REPEATABLE_READ)
- the first operation's class is marked with
@Transactional
How does Spring behave in terms of managing transactions when calling the second operation?
Code description
@Service
@Transactional
class Service1 {
@Autowired MyRepo repo;
void read(String id) {
repo.findById(id);
}
}
@Service
@Transactional
class Service2 {
@Autowired Service1 readCommittedService;
@Autowired MyRepo repo;
@Transactional(isolation=Isolation.REPEATABLE_READ)
void whatHappensNow(String id) {
readCommittedService.read(id);
repo.modifyRow(id);
}
}
What happens when we call service2.whatHappensNow("foo")
?
Will Spring create a transaction, with REPEATABLE_READ
isolation, and use that same isolation level when calling the repository via the service1.read("foo")
?
And if a concurrent request is received, but this time it's a direct call to service1.read("foo")
: will that transaction have the appropriate READ_COMMITTED
isolation level, thus having no chance of failing or being blocked by that other request coming from service2
?