Spring允许您通过事务传播机制来控制逻辑和物理事务的行为。您可以在Spring应用程序中通过设置七种事务传播机制org.springframework.transaction.annotation.Propagation。
org.springframework.transaction.annotation.Propagation
默认情况下,导致事务回滚的唯一异常是未经检查的异常(如RuntimeException)。不过,你可以通过控制这方面noRollbackFor,noRollbackForClassName,rollbackFor,和rollbackForClassName元素@Transactional。
noRollbackFor,noRollbackForClassName
rollbackFor
rollbackForClassName
@Transactional
Propagation.REQUIRED Propagation.REQUIRED是@Transactional注释的默认设置。的REQUIRED传播可以被解释如下:
考虑以下两个逻辑事务(或将其视为包含内部逻辑事务的一个外部逻辑事务):
@Transactional(propagation=Propagation.REQUIRED) public void insertFirstAuthor() { Author author = new Author(); author.setName("Joana Nimar"); authorRepository.save(author); insertSecondAuthorService.insertSecondAuthor(); }
@Transactional(propagation = Propagation.REQUIRED) public void insertSecondAuthor() { Author author = new Author(); author.setName("Alicia Tom"); authorRepository.save(author); if(new Random().nextBoolean()) { throw new RuntimeException("DummyException: this should cause rollback of both inserts!"); } }
步骤1:insertFirstAuthor()调用该方法时,没有物理事务。Spring创建了一个用于执行外部逻辑事务的方法(该方法的代码)。
insertFirstAuthor()
第2步:insertSecondAuthor()从中调用时insertFirstAuthor(),存在一个现有的物理事务。因此,Spring邀请该insertSecondAuthor()方法表示的内部逻辑事务参与此物理事务。
insertSecondAuthor()
第3步:如果RuntimeException引发了insertSecondAuthor()方法末尾的随机原因,那么Spring将回滚这两个逻辑事务。因此,什么都不会插入数据库中。
RuntimeException
下图描述了Propagation.REQUIRED流向:
捕获和处理RuntimeException中insertFirstAuthor()仍然会回滚外逻辑事务。发生这种情况是因为内部逻辑事务设置了仅回滚标记,并且由于两个逻辑事务的作用域都映射到同一物理事务,所以外部逻辑事务也被回滚。Spring将静默回滚两个逻辑事务,然后引发以下异常:
org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only.
外部逻辑事务需要接收,UnexpectedRollbackException以清楚地指示已执行内部逻辑事务的回滚,因此也应回滚。
UnexpectedRollbackException
Propagation.REQUIRES_NEW Propagation.REQUIRES_NEW指示Spring容器始终创建一个新的物理事务。这样的事务也可以声明自己的超时,只读和隔离级别设置,而不继承外部物理事务的特征。
下图描述了Propagation.REQUIRES_NEW流程:
请注意如何处理此方面,因为每个物理事务都需要其自己的数据库连接。因此,外部物理事务将具有其自己的数据库连接,而REQUIRES_NEW将创建内部物理事务并将绑定新的数据库连接。在同步执行中,内部物理事务在运行时,外部物理事务被挂起,并且其数据库连接保持打开状态。内部物理事务提交后,将恢复外部物理事务,继续运行并提交/回滚。
如果内部实物交易回滚,则可能会或可能不会影响外部实物交易。
@Transactional(propagation = Propagation.REQUIRES_NEW) public void insertSecondAuthor() { Author author = new Author(); author.setName("Alicia Tom"); authorRepository.save(author); if(new Random().nextBoolean()) { throw new RuntimeException ("DummyException: this should cause rollback of second insert only!"); } }
步骤1:当您调用时insertFirstAuthor(),将创建第一个物理交易(外部),因为没有现有的物理交易。
步骤2:当insertSecondAuthor() 从中调用时insertFirstAuthor(),Spring将创建另一个物理事务(内部)。
步骤3:如果RuntimeException抛出,则两个物理事务(内部第一个和外部之后)都将回滚。发生这种情况是因为抛出的异常 insertSecondAuthor() 会传播到调用方,insertFirstAuthor()从而也会导致外部物理事务回滚。如果这不是理想的行为,并且您只想回退内部物理事务而不影响外部物理事务,则需要捕获并处理RuntimeExceptionin insertFirstAuthor(),如下所示:
RuntimeExceptionin insertFirstAuthor()
@Transactional(propagation = Propagation.REQUIRED) public void insertFirstAuthor() { Author author = new Author(); author.setName("Joana Nimar"); authorRepository.save(author); try { insertSecondAuthorService.insertSecondAuthor(); } catch (RuntimeException e) { System.err.println("Exception: " + e); } }
即使内部物理事务回滚,外部物理事务也会提交。
如果在提交内部物理事务之后回滚外部物理事务,则内部物理事务不会受到影响。
Propagation.NESTED NESTED就像一样REQUIRED,只是它在嵌套调用之间使用保存点。换句话说,内部逻辑事务可以独立于外部逻辑事务回滚。
下图描述了Propagation.NESTED流程:
尝试NESTED与Hibernate JPA一起使用将导致Spring异常,如下所示:
NestedTransactionNotSupportedException: JpaDialect does not support savepoints - check your JPA provider capabilities
发生这种情况是因为Hibernate JPA不支持嵌套事务。
导致异常的Spring代码是:
private SavepointManager getSavepointManager() { ... SavepointManager savepointManager = getEntityManagerHolder().getSavepointManager(); if (savepointManager == null) { throw new NestedTransactionNotSupportedException("JpaDialect does not support ..."); } return savepointManager; }
一种解决方案是使用JdbcTemplate或支持嵌套事务的JPA提供程序。您也可以使用jOOQ。
JdbcTemplate
Propagation.MANDATORY Propagation.MANDATORY需要现有的物理事务或将导致异常,如下所示:
Propagation.MANDATORY
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'.
下图描述了Propagation.MANDATORY流程:
考虑以下代码:
@Transactional(propagation = Propagation.MANDATORY) public void insertSecondAuthor() { Author author = new Author(); author.setName("Alicia Tom"); authorRepository.save(author); if (new Random().nextBoolean()) { throw new RuntimeException("DummyException: this should cause rollback of both inserts!"); } }
当insertSecondAuthor()从调用insertFirstAuthor(),有一种现有的物理交易(通过创建Propagation.REQUIRED)。此外,由insertSecondAuthor()代码表示的内部逻辑事务将参与此物理事务。如果此内部逻辑事务回滚,则外部逻辑事务也将回滚,与的情况完全相同Propagation.REQUIRED。
Propagation.REQUIRED
Propagation.NEVER Propagation.NEVER指出不应该存在任何实物交易的状态。如果找到实物交易,NEVER则将导致如下异常:
Propagation.NEVER
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
下图描述了Propagation.NEVER流程:
查看以下代码:
@Transactional(propagation = Propagation.NEVER) public void insertFirstAuthor() { Author author = new Author(); author.setName("Joana Nimar"); authorRepository.save(author); }
第1步: 当insertFirstAuthor()被调用时,弹簧搜索现有的实物交易。
第2步:由于没有可用的Spring,因此Spring将不会导致异常,并且将在物理事务之外运行此方法的代码。
步骤3:当代码到达save()方法时,Spring将打开一个物理事务,尤其是用于运行此调用的事务。发生这种情况是因为save()利用了default Propagation.REQUIRED。
save()
default Propagation.REQUIRED
当调用带有注释的方法时NEVER,必须确保没有打开任何物理事务。此方法中的代码可以毫无问题地打开物理事务。
Propagation.NOT_SUPPORTED Propagation.NOT_SUPPORTED声明如果存在实物交易,则将其暂停,然后再继续。此实际交易将在最后自动恢复。恢复该事务后,可以回滚(如果发生故障)或提交该事务。
Propagation.NOT_SUPPORTED
下图描述了Propagation.NOT_SUPPORTED流程:
让我们看一些代码:
@Transactional(propagation = Propagation.REQUIRED) public void insertFirstAuthor() { Author author = new Author(); author.setName("Joana Nimar"); authorRepository.save(author); insertSecondAuthorService.insertSecondAuthor(); }
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void insertSecondAuthor() { Author author = new Author(); author.setName("Alicia Tom"); authorRepository.save(author); if (new Random().nextBoolean()) { throw new RuntimeException("DummyException: this should cause " + "rollback of the insert triggered in insertFirstAuthor() !"); } }
步骤1:当insertFirstAuthor()被调用时,没有可用的物理交易。因此,Spring将创建一个符合以下条件的事务:Propagation.REQUIRED.
Propagation.REQUIRED.
步骤2:此外,代码触发插入(作者Joana Nimar保留在数据库中)。
步骤3:insertSecondAuthor()从调用该语句insertFirstAuthor(),Spring必须评估的存在Propagation.NOT_SUPPORTED。现有的实物交易;因此,在继续之前,Spring将暂停它。
步骤4:在insertSecondAuthor()任何物理事务之外执行来自的代码,直到流程触及save()调用为止。默认情况下,此方法处于Propagation.REQUIRED保护范围之内;因此,Spring创建一个物理事务,执行INSERT(对于Alicia Tom),并提交此事务。
步骤5:将insertSecondAuthor()剩余的代码被执行的物理事务之外。
步骤6: 在后 insertSecondAuthor() 代码完成,弹簧恢复暂停的物理交易和恢复的执行insertFirstAuthor()它离开的地方逻辑事务。如果将RuntimeException抛出insertSecondAuthor(),则此异常将在中传播insertFirstAuthor(),并且此逻辑事务将回滚。
即使由于暂停了事务Propagation.NOT_SUPPORTED,您仍应努力避免长时间运行的任务。请注意,在事务挂起时,附加的数据库连接仍处于活动状态,因此池连接无法重用它。换句话说,即使数据库连接的绑定事务被挂起,它也处于活动状态:
... Suspending current transaction HikariPool-1 - Pool stats (total=10, active=1, idle=9, waiting=0) Resuming suspended transaction after completion of inner transaction
Propagation.SUPPORTS
Propagation.SUPPORTS声明如果存在物理事务,则它将在此物理事务的上下文中将划定的方法作为逻辑事务执行。否则,它将在物理事务之外执行此方法。让我们看一些代码:
@Transactional(propagation = Propagation.SUPPORTS) public void insertSecondAuthor() { Author author = new Author(); author.setName("Alicia Tom"); authorRepository.save(author); if (new Random().nextBoolean()) { throw new RuntimeException("DummyException: this should cause rollback of both inserts!"); } }
步骤1:当insertFirstAuthor()被调用时,没有可用的物理交易。因此,Spring将创建一个符合的事务Propagation.REQUIRED。
步骤2:此外,Spring开始执行该insertFirstAuthor()方法表示的外部逻辑事务,并通过该方法触发插入 save() (作者Joana Nimar保留在数据库中)。
步骤3:insertSecondAuthor()从中调用insertFirstAuthor(),Spring必须评估的存在Propagation.SUPPORTS。存在现有的实物交易。因此,from的代码insertSecondAuthor()在此物理事务的上下文中作为内部逻辑事务执行。如果RuntimeException抛出a,则内部和外部逻辑事务都会回滚。
捕获和处理RuntimeExceptionininsertFirstAuthor()仍会回滚外部逻辑事务。发生这种情况是因为内部逻辑事务设置了仅回滚 标记,并且两个逻辑事务的范围都映射到同一物理事务。
RuntimeExceptionininsertFirstAuthor()
下图描述了Propagation.SUPPORTS流程:
让我们@Transactional(propagation = Propagation.REQUIRED)从中删除insertFirstAuthor()并再次评估流程:
@Transactional(propagation = Propagation.REQUIRED
第1步:当 insertFirstAuthor()被调用时,没有实物交易可用,因为春天不会创建一个@Transactional缺失。
步骤2:从此代码insertFirstAuthor()开始在物理事务之外执行,直到流程触及save()调用为止。默认情况下,此方法处于保护Propagation.REQUIRED之下,因此Spring将创建一个物理事务,执行插入操作(对于Joana Nimar),然后提交此事务。
第3步:当insertSecondAuthor()从叫insertFirstAuthor(),春天将需要评估的存在Propagation.SUPPORTS。目前没有实际交易,Spring不会创建符合该Propagation.SUPPORTS定义的交易。
步骤4:直到流程中的save()方法生效为止insertSecondAuthor(),代码将在物理事务之外执行。默认情况下,save()它处于保护Propagation.REQUIRED 之下,因此Spring创建一个物理事务,执行插入操作(对于Alicia Tom),并提交此事务。
Spring
Alicia Tom
第5步:当RuntimeException被抛出,没有实物交易,所以没有被回滚。
原文链接:http://codingdict.com