Spring 的事务传播机制
一、什么是事务传播机制?
事务传播机制,顾名思义就是多个事务方法之间调用,事务如何在这些方法之间传播,是重新创建事务还是使用父方法的事务,父方法的回滚对子方法的事务是否有影响等等,这些都是事务传播机制决定的。
二、Spring 事务传播特性有哪些?
多个事务方法相互调用时,事务如何在这些方法之间进行传播呢?Spring 提供了 7 种不同的传播特性,来保证事务的正常进行。源码如下所示。
package org.springframework.transaction.annotation;public enum Propagation {REQUIRED(0),SUPPORTS(1),MANDATORY(2),REQUIRES_NEW(3),NOT_SUPPORTED(4),NEVER(5),NESTED(6);private final int value;private Propagation(int value) {this.value = value;}public int value() {return this.value;}
}
Propagation(传播特性)有以下选项可供使用:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。
在陈述传播特性之前,以如下伪代码为例,陈述几个术语。
ServiceA.methodA(required){// methodA 方法的业务ServiceB.methodB(required);
}
ServiceA 中的 methodA 方法调用 ServiceB 中的 methodB 方法,ServiceA.methodA 方法的事务被称为 “当前事务”(current transaction,有些文章中也称为父事务或外部事务),ServiceB.methodB 方法的事务被称为子事务(或内部事务)。上述伪代码设置了当前事务传播特性为 REQUIRED,子事务传播特性为 REQUIRED。
Spring 的几种事务传播特性含义如下(均站在子方法的立场而言,即上述伪代码中的 methodB)。
REQUIRED
这是 Spring 默认的传播特性。如果当前没有事务,则新建一个事务;如果当前存在事务,则加入这个事务。这是实际项目开发中最常见的配置。
例如,ServiceA.methodA 的事务传播特性定义为 Propagation.REQUIRED,ServiceB.methodB 的事务传播特性定义为 Propagation.REQUIRED,那么由于执行 ServiceA.methodA 的时候,ServiceA.methodA 已经起了事务,这时调用 ServiceB.methodB,ServiceB.methodB 看到自己已经运行在 ServiceA.methodA 的方法内部,就不再起新的事务,而是加入当前事务。这样,在 ServiceA.methodA 或者在 ServiceB.methodB 内的任何地方出现异常,事务都会被回滚,即使 ServiceB.methodB 的事务已经被提交,但是 ServiceA.methodA 在接下来异常要回滚,ServiceB.methodB 也要回滚。SUPPORTS
如果存在当前事务,即以事务的形式运行,如果当前没有事务,则以非事务的方式执行。MANDATORY
存在当前事务,则加入当前事务,如果没有当前事务,就抛出异常。
必须在一个事务中运行,也就是说,它只能被一个父事务调用,否则子方法就抛出异常。REQUIRES_NEW
创建一个新事务,如果存在当前事务,则把当前事务挂起。例如,我们设计 ServiceA.methodA 的事务传播特性为 Propagation.REQUIRED,ServiceB.methodB 的事务传播特性为 Propagation.REQUIRES_NEW,那么当执行到 ServiceB.methodB 的时候,ServiceA.methodA 所在的事务就会挂起,ServiceB.methodB 会起一个新的事务,等到 ServiceB.methodB 的事务完成以后,ServiceA.methodA 所在的事务才继续执行。它与 REQUIRED 的事务区别在于事务的回滚程度。因为 ServiceB.methodB 是新起一个事务,相当于存在两个不同的事务。如果 ServiceB.methodB 已经提交,那么 ServiceA.methodA 失败回滚,ServiceB.methodB 是不会回滚的。如果 ServiceB.methodB 失败回滚,如果它抛出的异常被 ServiceA.methodA 捕获,ServiceA.methodA 事务仍然可能提交。NOT_SUPPORTED
以非事务方式执行操作,如果存在当前事务,就把当前事务挂起。例如,ServiceA.methodA 的事务传播特性是 Propagation.REQUIRED,而 ServiceB.methodB 的事务传播特性是 Propagation.NOT_SUPPORTED,那么当执行到 ServiceB.methodB 时,ServiceA.methodA 的事务挂起,而 ServiceB.methodB 以非事务的状态运行完,再继续 ServiceA.methodA 的事务。NEVER
不使用事务,以非事务方式执行。如果当前事务存在,则抛出异常,不能在事务中运行。假设 ServiceA.methodA 的事务传播特性是 Propagation.REQUIRED,而 ServiceB.methodB 的事务传播特性是 Propagation.NEVER ,那么 ServiceB.methodB 就要抛出异常了。NESTED
如果当前事务存在,就运行一个嵌套事务。如果不存在当前事务,就和 REQUIRED 一样新建一个事务。
三、部分事务的不同点
3.1 NESTED 和 REQUIRES_NEW 的区别
REQUIRES_NEW 是新建一个事务,并且新开始的这个事务和当前事务无关,当前事务回滚,不会影响到 REQUIRES_NEW 事务。
而 NESTED 是一个嵌套事务,是父事务的一个子事务。当前事务存在时,NESTED 会开启一个嵌套事务。
在 NESTED 情况下,父事务回滚时,子事务也会回滚,而 REQUIRES_NEW 情况下,原有事务回滚,不会影响新开启的事务。
3.2 NESTED 和 REQUIRED 的区别
REQUIRED 情况下,当前事务存在时,被调用方和调用方使用同一个事务,那么被调用方出现异常时,由于共用一个事务,所以无论是否 catch 异常,事务都会回滚。
而 NESTED 情况下,被调用方发生异常时,调用方可以 catch 其异常,这样只有子事务回滚,父事务不会回滚。
四、测试验证
为了验证传播特性的准确性,笔者采用 Springboot,分别编写了上述伪代码中的两个测试方法,即调用方 ServiceA.saveA 方法和被调用方 ServiceB.saveB 方法,详见下方代码。
package com.test.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.test.entity.Stat;
import com.test.dao.sconl.StatMapper;import javax.annotation.Resource;@Service
public class ServiceA {@Resourcepublic StatMapper statMapper;@Resourcepublic ServiceB serviceB;@Transactional(value = "sconlTransactionManager", propagation = Propagation.REQUIRED)public void saveA() {Stat stat = new Stat();stat.setStatId("0001");stat.setStatNm("0001");int resultA = statMapper.insertSelective(stat);System.out.println(resultA);// 调用 B 服务的方法try {serviceB.saveB();} catch (Exception e) {e.printStackTrace();}// throw new RuntimeException("ExceptionA");}
}
package com.test.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.test.entity.OrderInfo;
import com.test.dao.sconl.OrderMapper;import javax.annotation.Resource;@Service
public class ServiceB {@Resourcepublic OrderMapper orderMapper;@Transactional(value = "sconlTransactionManager", propagation = Propagation.NESTED)public void saveB() {OrderInfo orderInfo = new OrderInfo();orderInfo.setOrderId("orderId");int resultB = orderMapper.insertSelective(orderInfo);System.out.println(resultB);// throw new RuntimeException("ExceptionB");}
}
上述两个测试类均采用声明式事务,通过 @Transactional 标签来声明事务,标签中的 value 属性设置事务管理器,propagation 属性设置事务传播特性,方法内部通过 throw new RuntimeException(“ExceptionB”) 来抛出异常。默认情况下,RuntimeException 异常会导致事务回滚。通过改变当前事务和子事务的传播特性,以及设置 saveA 和 saveB 方法内部是否抛出异常,来测试当前事务和子事务之间的事务传播特性。
经过测试,结果和理论相符。下表总结下不同的事务传播特性和异常状态对结果的影响。
ServiceA.saveA() 以 Propagation.REQUIRED 修饰,ServiceB.saveB() 以表格中三种属性修饰,测试结果和一些关键性日志如下表所示(异常状态一列中,均以 A 表示 ServiceA.saveA() 方法,以 B 表示 ServiceB.saveB() 方法)。
异常状态 | REQUIRED | REQUIRES_NEW | NESTED |
---|---|---|---|
A正常 B正常 |
A提交 B提交 |
A提交 B提交 |
A提交 B提交 |
A正常 B异常 |
A回滚 B回滚 |
A提交 B回滚 |
A提交 B回滚 Rolling back transaction to savepoint |
A异常 B正常 |
A回滚 B回滚 |
A回滚 B提交 |
A回滚 B回滚 Releasing transaction savepoint |
A异常 B异常 |
A回滚 B回滚 |
A回滚 B回滚 |
A回滚 B回滚 |
测试时,将 logback 的应用日志级别和 root 日志级别设置为 DEBUG,则可以看到具体的事务信息。
将子事务设置为 REQUIRED 时,一些关键性日志如下所示:
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d093edf] from current transaction
将子事务设置为 REQUIRES_NEW 时,一些关键性日志如下所示:
Suspending current transaction, creating new transaction with name [com.test.service.ServiceB.saveB]Resuming suspended transaction after completion of inner transaction
将子事务设置为 NESTED 时,一些关键性日志如下所示:
Creating nested transaction with name [com.test.service.ServiceB.saveB]Releasing transaction savepoint
五、测试时踩过的坑
笔者在实际代码中测试时,由于踩了一些坑,导致事务传播效果和理论不符,现在简单记录下来。
5.1 多数据源情况下未指明事务管理器
笔者在多数据源项目中做测试,开始时未在事务标签中通过 value 属性指明事务管理器,出现了和理论不符的测试效果。后来在父方法和子方法中均指明了实际的数据源事务管理器,测试效果才和理论相符。
5.2 方法修饰符设置成 private
开始时部分方法的修饰符设置为 private,导致事务失效,效果和理论不符。为了能被 AOP 事务增强,方法修饰符须为 public。
5.3 父事务方法未捕获子事务方法的异常
开始时,父方法内部调用子方法时,未通过 try - catch 捕获子方法的异常,导致效果和理论不符。后来在 ServiceA.saveA() 方法内部调用 ServiceB.saveB() 时,用 try - catch 捕获了子事务方法的异常,测试效果终和理论相符了。
文章参考:
- 一文搞懂spring boot本地事务@Transactional参数
- SpringBoot事务传播属性测试
- Spring事务的传播特性引发的一场血案
Spring 的事务传播机制相关推荐
- spring上下文是什么意思_Java程序员只会CRUD连Spring事务传播机制都不懂?
AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东西,面试完就 ...
- 原创 | CRUD更要知道的Spring事务传播机制
来自:肥朝 AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东 ...
- Spring事务与事务传播机制
目录 1.事务的基本概念 2.Spring事务的实现 3.事务隔离级别 4.事务传播机制 1.事务的基本概念 关于事务的一些基础概念我已经在MYSQL中讲解过了,有不了解的可以移步至此篇文章: MyS ...
- Spring事务传播机制大白话(使用springboot,注解演示)
1. 我对传播机制的理解 为什么需要传播机制? 因为事务之间可能存在相互调用,例如service业务层的方法存在相互调用,如果相互调用的方法都开启了事务(对应到springboot就是在方法上要添加@ ...
- 【Spring事务】事务和事务传播机制
事务 事务主要有三种操作: 开始事务 start transaction 提交事务 commit 回滚事务 rollback Spring 中事务的实现 Spring 中的事务操作分为两类: ⼿动操作 ...
- SpringBoot事务传播机制
6.Spring的事务传播机制: 1)定义:咱们之前所说的事务,都是针对一个方法的,咱们的Spring事务传播机制,不再是单个的事务了,咱们的Spring事务传播机制定义了包含多个方法相互调用的时候, ...
- Spring事务传播机制和隔离级别
Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非常的绕.如果栽在这上面,就实在是太可惜了. @Transactional(is ...
- java spring 事务传播_spring事务传播机制实例讲解
天温习spring的事务处理机制,总结如下 对于SQL事务的概念以及ACID性质,可以参见我的另一篇博文 http://kingj.iteye.com/admin/blogs/1675011 spri ...
- Spring 事务传播机制 实例讲解
事务传播机制 对于SQL事务的概念以及ACID性质,可以参见我的另一篇博文 http://kingj.iteye.com/admin/blogs/1675011 spring的管理的事务可以分为如下2 ...
- Spring事务传播机制以及事务嵌套
Spring事务传播机制以及事务嵌套 Spring事务传播机制 事务嵌套场景 情景0: 场景1:不同类中,开启事务的方法调用没有开启事务的方法 场景2:不同类中,methodA方法嵌套methodB方 ...
最新文章
- springboot 订单重复提交_Spring Boot (一) 校验表单重复提交
- 在面向数据流的设计方法中,一般把数据流图中的数据流划分为 (16) 两种。 答案:C
- 用一个创业故事串起操作系统原理(一)
- Python中将数据矢量化运算所带来的时间加快
- 【Python】 Spyder
- Visual Studio 2005 Service Pack 1 正式版发布
- python 装饰函数
- 12c分页查询特性FETCH FIRST ROWS,OFFSET ROWS FETCH NEXT ROW LIMIT Clause子句
- 微服务框架Demo.MicroServer运行手册
- CF932E-Team Work【斯特林数,组合数学】
- c#做端口转发程序支持正向连接和反向链接
- php 开启coredump,GDB分析PHP连接Memcached 导致coredump问题
- 如何估算太坊交易的gas消耗量
- [转载] python 运算符重载有什么用_Python运算符重载用法实例分析
- 3dmax2020卸载/安装失败/如何彻底卸载清除干净3dmax2020注册表和文件的方法
- Java项目:SSM问卷调查系统
- python 档案管理系统_用Python编写人才档案管理系统?
- 如何下载windows自带的锁屏壁纸
- 网站的robots 文件写法 附自动生成工具网址
- 对 COMP 通证经济模型的一般性评价
热门文章
- linux系统sdio接口wifi编程,3个SDIO接口WiFi模块/WiFi+蓝牙组合模块介绍-SKYLAB
- CentOS7.5.1804 Minimal 静默安装oracle 12c R1企业版
- Chapter3 Language Basics
- 国内外优秀呼叫中心系统简介
- ui设计网站资料大全,你想要的都有
- python正则匹配中文
- vector初始化方法(待补充)
- python网络爬虫最细致讲解之漫画抓取【细!!!】
- 计算机excel高级筛选操作大全,Excel高级筛选的7个使用实例,含不等于空、多条件、筛选到另一表格、用通配符*/?或公式组合条件...
- 2021-01-18