Spring @Transactional隔离传播

时间:2017-11-30 13:26:54

标签: java spring spring-boot spring-data-jpa transactional

可以在同一交易

之间更改隔离级别

我有一个用例,我想要使用SpringDataJpa的saveAndFlush持久化的未提交数据在不同的事务中可用或者使内部事务提交数据但是应该能够在发生任何异常的情况下回滚外部交易

这是必需的,因为我想更新资源,并且在锁定表中有一个条目以避免并发更新。 DB中的锁定表没有得到更新,直到Update事务完成,因此我想将数据提交到锁定表,同时应该在更新操作期间出现任何异常时回滚。

  1. 具有@Transactional的Service1方法将调用Service2的方法。 Service2有@Transactional(隔离= Isolation.READ_UNCOMMITTED),后者又会调用存储库。
  2. 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。
    2. 如果TX1执行了saveAndFlush但尚未提交给DB(因为TX1尚未完成),TX2是否可以访问未提交的数据?

      1. 如果启动交易后无法更改隔离
      2. 是否有使用传播或隔离(或任何其他方法)的方法,使用该方法可以单独提交内部事务,但是如果外部事务中有任何异常,也可以回滚?

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

        Service2方法的PROPAGATION_NESTED - 仅在Service1 tx提交时提交数据

        有没有办法实现顶部BOLD中突出显示的用例?

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

1 个答案:

答案 0 :(得分:0)

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

如果您有多个dB状态需要单独还原,这种方法很难,但现在就足够了