Skip to content

Doc: @Transactional.isolation does not guarantee the specified isolation level [SPR-16463] #21008

Closed
@spring-projects-issues

Description

@spring-projects-issues

Valentin Kovalenko opened SPR-16463 and commented

Let's imagine two bean methods:

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
public void methodA(Runnable action) {
  jdbc.execute("select 'inside methodA before methodB'");
  action.run();
  jdbc.execute("select 'inside methodA after methodB'");
}
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE)
public void methodB() {
  jdbc.execute("select 'inside methodB'");
}

and we want to use them like this:

public void use() {
  bean.methodA(bean::methodB);
}

This is a tricky case: it can't be implemented without violating the semantics of either Transactional.propagation or Transactional.isolation, because modern RDBMS do not allow changing an isolation level in the middle of a transaction, and Spring does not even try doing this. A user, however, may not realize this fact, or may not realize the fact that he actually has the situation bean.methodA(bean::methodB) in his project. Thus the user may believe that methodB is always executed in a transaction context with Isolation.SERIALIZABLE, which does not happen to be true.

The same is true not only for Propagation.REQUIRED, but also for Propagation.MANDATORY. This means that annotating a method with @Transactional(propagation = Propagation.MANDATORY, isolation = Isolation.SERIALIZABLE) does not guarantee that the method will be executed in a transaction context with Isolation.SERIALIZABLE.

I think that such behaviour violates the principle of least astonishment and may easily lead to bugs related to a usage of an incorrect isolation level. However, it may not be a good idea to always throw an exception when Spring cannot guarantee the demanded level of isolation. Possibly this can be solved by throwing an exception by default but providing a way to disable it by explicitly specifying which semantics the Spring framework should violate in such situations: Transactional.propagation or Transactional.isolation. I believe the solution definitely requires discussing.

The complete description of this situation can be found here: https://sites.google.com/site/aboutmale/techblog/transactionalcatch


Affects: 4.3.14

Issue Links:

Referenced from: commits cc77b4b, 0ac117f, f789895

Backported to: 4.3.15

Metadata

Metadata

Assignees

Labels

in: dataIssues in data modules (jdbc, orm, oxm, tx)status: backportedAn issue that has been backported to maintenance branchestype: taskA general task

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions