简体   繁体   English

Spring @事务隔离传播

[英]Spring @Transactional Isolation propagation

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 我有一个用例,我希望使用SpringDataJpa的saveAndFlush持久化的未提交数据可在不同事务中使用,或者使内部事务提交数据,但在外部事务中发生任何异常的情况下应该能够回滚

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. 具有@Transactional的Service1方法将调用Service2的方法。 Service2 have @Transactional(isolation=Isolation.READ_UNCOMMITTED) which in turn will call the repository. Service2具有@Transactional(isolation = Isolation.READ_UNCOMMITTED),后者将依次调用存储库。

Does the Service2 Isolation of READ_UNCOMMITED will take precedence or the Default one? READ_UNCOMMITED的Service2隔离是优先还是默认?

Does this Change in Isolation reflect in same Transaction that was propagated from Service1? 此隔离更改是否反映在从Service1传播的同一事务中?

Scenario 1: 方案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: 方案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. 让线程1启动TX1,线程2启动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)? 万一TX1执行了saveAndFlush但尚未提交给DB(因为TX1尚未完成),TX2可以访问未提交的数据吗?

  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 Service2方法上的PROPAGATION_REQUIRES_NEW-将提交数据,但如果Service1中发生任何异常,它将不会回滚

PROPAGATION_NESTED on Service2 method - will commit data only when Service1 tx will commit Service2方法上的PROPAGATION_NESTED-仅在Service1 tx提交时提交数据

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 有关伪代码,请参阅Scenario2。

The scenario 2 where in ..Propagation Require_New ..Is what I have used. 在..Propagation Require_New ..中的场景2是我使用的。 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. 并且在父方法期间发生任何运行时异常的情况下,我已经在try catch中处理了该异常,并还原了作为新事务的一部分在数据库中更新的锁,并将相同的异常抛出到catch块中,以便还原父事务太。

This approach will be difficult in case you have many dB states to be reverted by you individually, but for now it suffice 万一您有许多dB状态需要单独恢复,这种方法将很困难,但是目前就足够了

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM