Spring嵌套事务原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring嵌套事务原理相关的知识,希望对你有一定的参考价值。

参考技术A Spring 采用保存点(Savepoint)实现嵌套事务原理

Spring采用一个物理事务,但是结合着savepoint机制( mysql中称为保存点 )实现一个事务中的指定范围提交。
当某个方法将Spring事务传播级别设置为PROPAGATION_NESTED的时候,如果创建事务时已经存在了一个事务,则会创建一个嵌套事务。

//创建保存点
AbstractPlatformTransactionManager. handleExistingTransaction
status.createAndHoldSavepoint();

//提交事务成功释放保存的保存点
AbstractPlatformTransactionManager.processCommit
status.releaseHeldSavepoint();

//如果有保存点,同样是对当前保存点进行回滚,
//依此达到部分回滚的功能
AbstractPlatformTransactionManager. processRollback
status.rollbackToHeldSavepoint();

案例:
解惑 spring 嵌套事务

不论使用REQUIRES_NEW或是NESTED,在调用B的invoke时如果发生异常,都能正确完成业务逻辑

Spring事务之传播机制

Spring事务传播机制:
Spring在TransactionDefinition接口中规定了种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套时事务如何进行传播。
即协调已经有事务标识的方法之间的发生调用时的事务上下文的规则(是否要有独立的事务隔离级别和锁)。

事务的嵌套概念:
所谓事务的嵌套就是两个事务方法之间相互调用。Spring事务开启,或者是基于接口的,或者是基于类的代理被创建(注意一定要是代理,
不能手动new一个对象,并且此类(有无接口都行)一定要被代理————Spring中的bean只要纳入了IOC管理都是要被代理的)。
所以在同一个类中一个方法调用另一个有事务的方法,事务是不会起作用的。

概述:
当我们调用一个基于Spring的Service接口方法(如UserService#addUser())时,它将运行于Spring管理的事务环境中,
Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作,因为就会产生服务接口方法
嵌套调用的情况,Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。

事务传播是Spring进行事务管理的重要概念。在下文中将详细分析不同事务传播行为的表现形式,掌握他们之间的区别。

一、事务传播行为种类

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套时事务如何进行传播:

如下为 org.springframework.transaction.TransactionDefinition接口。

package org.springframework.transaction;

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;

    int getPropagationBehavior();//事务的传播行为

    int getIsolationLevel();//事务的隔离级别

    int getTimeout();//事务的过期时间

    boolean isReadOnly();//事务的读写特性

    String getName();//获取名称
}

01. required:是Spring默认的事务传播行为。指定的方法必须在事务内执行,如果没有事务,自动创建事务并执行。

02. support:有没有事务都执行,有事务就在事务中执行,否则直接执行。

03. mandatory:如果当前存在事务,就执行该事务,如果当前不存在事务,就抛出异常。

04. requires_new:总是创建新事务,如果当前方法存在事务,则将当前方法事务先挂起(先执行新创建的事务,再执行被挂起的当前方法本身的事务),直到新创建的事务执行完毕。

05. not_supported:不能再事务中执行,如果当前方法存在事务,则将当前方法事务挂起。

06. never :不能在事务中执行,如果当前方法存在事务,则会抛出异常。

07. nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与require类似的操作。

注意:

requires_new 是启动一个新的,不依赖于环境的“内部”事务。

这个事务将被完全commited或者rollback而不依赖于外部事物,它拥有自己的隔离范围,自己的锁等等。当内部事务开始执行时,外务事务将会被挂起,内部事务结束时,外部事物将继续执行。

另一方面,nested是开始一个“嵌套的”事务,它是已经存在的事务的一个真正的子事务。嵌套事务开始执行时,它将取得一个savepoint。如果这个事务执行失败,我们将回滚到次savepoint,嵌套事务是外部事务的一部分,只有外部事务结束后嵌套事务才会被提交。(嵌套事务不能够提交,它必须通过外层事务来完成提交的动作,外层事务的回滚也会造成内部事务的回滚)

 

由此可见,requires_new 和 nested 最大的区别在于:

requires_new 完全是一个新的事务,而nested则是外部事务的子事务,如果外部事务commit,嵌套事务也会被commit,这个规则同样适用于rollback。

 

借助例子理解,请查看 https://www.cnblogs.com/softidea/p/5962612.html

 

以上是关于Spring嵌套事务原理的主要内容,如果未能解决你的问题,请参考以下文章

Spring嵌套事务控制

Spring嵌套事务

面试突击:加入事务和嵌套事务有什么区别?

Spring事务传播特性的浅析——事务方法嵌套调用的迷茫

Spring事务传播特性的浅析——事务方法嵌套调用的迷茫

知识点:Spring嵌套事务方式