Spring @Transactional 隔离传播

Spring @Transactional Isolation propagation

同一事务之间是否可以更改隔离级别

我有一个用例,我希望使用 SpringDataJpa 的 saveAndFlush 保存的未提交数据在不同的事务中可用,或者 使内部事务提交数据但应该能够回滚以防万一外部事务中的任何异常

这是必需的,因为我想更新资源并且在锁 table 中有一个条目以避免并发更新。在更新事务完成之前,数据库中的锁 table 不会更新,因此我想将数据提交到锁 table ,同时应该回滚以防更新操作期间出现任何异常.

  1. 具有@Transactional 的Service1 方法将调用Service2 的方法。 Service2 有 @Transactional(isolation=Isolation.READ_UNCOMMITTED) ,它又会调用存储库。

READ_UNCOMMITED 的 Service2 隔离优先还是默认隔离优先?

此隔离更改是否反映在从 Service1 传播的同一事务中?

场景 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>{
}

场景 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. 让Thread1启动TX1,Thread2启动TX2。

如果 TX1 执行了 saveAndFlush 但还没有提交到 DB(因为 TX1 还没有完成),TX2 可以访问未提交的数据吗?

  1. 如果事务启动后无法更改隔离

有没有一种方法可以使用传播或隔离(或任何其他方式)来单独提交内部事务,但也可以在外部事务出现任何异常时回滚?

PROPAGATION_REQUIRES_NEW Service2 方法 - 将提交数据,但如果 Service1 中出现任何异常,它不会回滚

PROPAGATION_NESTED Service2 方法 - 仅当 Service1 tx 提交时才会提交数据

有什么方法可以实现顶部以粗体突出显示的用例吗?

  1. 我现在尝试的解决方案是在更新的情况下必须处理任何异常,然后手动恢复数据库锁定操作。如果我们需要跟踪许多数据库提交并还原它们,这会很乏味。对于伪代码,请参考 Scenario2

场景2中..Propagation Require_New ..是我用过的。如果在父方法期间出现任何运行时异常,我已经在 try catch 中处理了该异常,并恢复了作为新事务的一部分在数据库中更新的锁,并在 catch 块中抛出相同的异常,以便恢复父事务也是。

如果您有许多 dB 状态要由您单独恢复,这种方法会很困难,但现在就足够了