1
votes

Can the Isolation level be changed between the Same Transaction

I have a usecase where I want either the uncommited data that was persisted using saveAndFlush of SpringDataJpa to be available across different Transactions OR make the Inner Transaction commit the data but should be able to rollback in case of any exception in the outer transaction

This is needed as I want to update a resource and would have an entry in lock table to avoid concurrent updates. The lock table in DB is not getting updated untill the Update transaction is getting completed , hence I want to commit the data to lock table and at the same time should rollback in case of any exceptions during update operation.

  1. Service1 method having @Transactional would call a method of Service2. Service2 have @Transactional(isolation=Isolation.READ_UNCOMMITTED) which in turn will call the repository.

Does the Service2 Isolation of READ_UNCOMMITED will take precedence or the Default one?

Does this Change in Isolation reflect in same Transaction that was propagated from Service1?

Scenario 1:

@Service
class Service1{
@Autowired
Service2 service2;
@Transactional
public void method1(){
Foo foo=new Foo();
foo.setId("f123");
service2.saveValue(foo);
}
}

@Service
@Transactional(isolation=Isolation.READ_UNCOMMITTED)
class Service2{
@Autowired
FooRepository fooRepository;

public void saveValue(Foo value){
fooRepository.saveAndFlush(value);
}
}

public interface FooRepository extends JpaRepository<Foo, String>{
}

Scenario 2:

@Service
class Service1{
@Autowired
Service2 service2;

@Transactional
public void method1(){

Foo foo=new Foo();
foo.setId("f123");
service2.saveValue(foo);

try{
updateOperation()
}catch(Throwable e){   // does Spring @Transactional revert on ERRORS, by default it rollback on RuntimeException and Exception(in case we explicitly mention)?
  service2.deleteByFooId(foo.getId());
  throw e;
}


}

private void updateOperation(){
 /* update logic for resource */- Not a DB update 

}



@Service
@Transactional(propagation=Propagation.REQUIRES_NEW)
class Service2{
@Autowired
FooRepository fooRepository;

public void saveValue(Foo value){
fooRepository.saveAndFlush(value);
}

public void delete(String id){
     deleteByFooId(id);
}
}

public interface FooRepository extends JpaRepository<Foo, String>{
}
  1. Let Thread1 started TX1 and Thread2 started TX2.

Can TX2 access the uncommited data in case TX1 has executed the saveAndFlush but not yet commited to DB(as TX1 is not yet completed)?

  1. If Isolation cannot be changed once Transaction is initiated

Is there a way using Propagation or Isolation (or any other means) using which the inner transaction can be commited individually but can also rollback in case of any exception in the outer Transaction?

PROPAGATION_REQUIRES_NEW on Service2 method - will commit the data but in case of any exception in Service1 it wont rollback

PROPAGATION_NESTED on Service2 method - will commit data only when Service1 tx will commit

Is there any way to achieve the usecase highlighted in BOLD at the top?

  1. The solution I am trying now is to have to handle any exception in case of updation and then revert the DB lock operation manually. This is tedious in case we need to track many DB commits and revert the same. For the pseudocode refer Scenario2
1
No you cannot change the isolation level of a running transaction.M. Deinum
@M.Deinum - Thanks for the quick response, can you please check my Update and suggest any solution for my use case highlighted in BOLDRaghav
Once a Thread touches the @ Transactional, inner @ Transactionals are ignored compleatly.Grim

1 Answers

0
votes

The scenario 2 where in ..Propagation Require_New ..Is what I have used. And in case of any runtime exception during the parent method, I have handled that exception in try catch and reverted the lock which is updated in the DB as part of the new transaction and threw the same exception in catch block so that parent transaction gets reverted too.

This approach will be difficult in case you have many dB states to be reverted by you individually, but for now it suffice