面试突击87:说一下 Spring 事务传播机制?
Spring 事务传播机制是指,包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。
既然是“事务传播”,所以事务的数量应该在两个或两个以上,Spring 事务传播机制的诞生是为了规定多个事务在传播过程中的行为的。比如方法 A 开启了事务,而在执行过程中又调用了开启事务的 B 方法,那么 B 方法的事务是应该加入到 A 事务当中呢?还是两个事务相互执行互不影响,又或者是将 B 事务嵌套到 A 事务中执行呢?所以这个时候就需要一个机制来规定和约束这两个事务的行为,这就是 Spring 事务传播机制所解决的问题。
Spring 事务传播机制有哪些?
Spring 事务传播机制可使用 @Transactional(propagation=Propagation.REQUIRED) 来定义,Spring 事务传播机制的级别包含以下 7 种:
- Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- Propagation.REQUIRES_NEW:表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
- Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。
以上 7 种传播机制,可根据“是否支持当前事务”的维度分为以下 3 类:

看到这里,有人可能会说:说了这么多,我也看不懂啊,即使看懂了,我也记不住啊?这要咋整?
没关系,接下来我们用一个例子,来说明这 3 类事务传播机制的区别。
以情侣之间是否要买房为例,我们将以上 3 类事务传播机制可以看作是恋爱中的 3 类女生类型:
- 普通型
- 强势型
- 懂事型
这三类女生如下图所示:

支持当前事务的“女生”,这里的事务指的是“房子”,它分为 3 种(普通型女生):
- Propagation.REQUIRED(需要有房子):有房子了咱们一起住,没房子了咱们一起赚钱买房子。
- Propagation.SUPPORTS(可以有房子):有房子了就一起住,没房子了咱们就一起租房子。
- Propagation.MANDATORY(强制有房子):有房子了就一起住,没房子了就分手。
不支持当前事务的“女生”也分为 3 种(强势型或者叫事业型):
- Propagation.REQUIRES_NEW:不要你的房子,必须一起赚钱买房子。
- Propagation.NOT_SUPPORTED:不要你的房子,必须一起租房子。
- Propagation.NEVER:必须一起租房子,你有房子就分手。
最后一种是嵌套性事务 Propagation.NESTED,它属于懂事型女友,如果有房子了就以房子为基础做点小生意,卖个花生、水果啥的,如果买卖成了,那就继续发展;如果失败了,至少还有房子;如果没房子也没关系,一起赚钱买房子。
事务传播机制使用与演示
接下来我们演示一下事务传播机制的使用,以下面 3 个最典型的事务传播级别为例:
- 支持当前事务的 REQUIRED;
- 不支持当前事务的 REQUIRES_NEW;
- 嵌套事务 NESTED。
下来我们分别来看。
事务传播机制的示例,需要用到以下两张表:
-- 用户表
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`createtime` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC;
-- 日志表
CREATE TABLE `log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` text NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
创建一个 Spring Boot 项目,核心业务代码有 3 个:UserController、UserServcie 以及 LogService。在 UserController 里面调用 UserService 添加用户,并调用 LogService 添加日志。
REQUIRED 使用演示
REQUIRED 支持当前事务。
UserController 实现代码如下,其中 save 方法开启了事务:
@RestController
public class UserController {
@Resource
private UserService userService;
@Resource
private LogService logService;
@RequestMapping("/save")
@Transactional
public Object save(User user) {
// 插入用户操作
userService.save(user);
// 插入日志
logService.saveLog("用户插入:" + user.getName());
return true;
}
}
UserService 实现代码如下:
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRED)
public int save(User user) {
return userMapper.save(user);
}
}
LogService 实现代码如下:
@Service
public class LogService {
@Resource
private LogMapper logMapper;
@Transactional(propagation = Propagation.REQUIRED)
public int saveLog(String content) {
// 出现异常
int i = 10 / 0;
return logMapper.saveLog(content);
}
}
执行结果:程序报错,两张表中都没有插入任何数据。
执行流程描述:
- 首先 UserService 中的添加用户方法正常执行完成。
- LogService 保存日志程序报错,因为使用的是 UserController 中的全局事务,所以整个事务回滚,步骤 1 中的操作也跟着回滚。
- 所以数据库中没有添加任何数据。
REQUIRED_NEW 使用演示
REQUIRED_NEW 不支持当前事务。
UserController 实现代码:
@RequestMapping("/save")
@Transactional
public Object save(User user) {
// 插入用户操作
userService.save(user);
// 插入日志
logService.saveLog("用户插入:" + user.getName());
return true;
}
UserService 实现代码:
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int save(User user) {
System.out.println("执行 save 方法.");
return userMapper.save(user);
}
}
LogService 实现代码:
@Service
public class LogService {
@Resource
private LogMapper logMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int saveLog(String content) {
// 出现异常
int i = 10 / 0;
return logMapper.saveLog(content);
}
}
程序执行结果:
User 表中成功添加了一条用户数据,Log 表执行失败,没有加入任何数据,但它并没有影响到 UserController 中的事务执行。
通过以上结果可以看出:LogService 中使用的是单独的事务,虽然 LogService 中的事务执行失败了,但并没有影响 UserController 和 UserService 中的事务。
NESTED 使用演示
NESTED 是嵌套事务。
UserController 实现代码如下:
@RequestMapping("/save")
@Transactional
public Object save(User user) {
// 插入用户操作
userService.save(user);
return true;
}
UserService 实现代码如下:
@Transactional(propagation = Propagation.NESTED)
public int save(User user) {
int result = userMapper.save(user);
System.out.println("执行 save 方法.");
// 插入日志
logService.saveLog("用户插入:" + user.getName());
return result;
}
LogService 实现代码如下:
@Transactional(propagation = Propagation.NESTED)
public int saveLog(String content) {
// 出现异常
int i = 10 / 0;
return logMapper.saveLog(content);
}
最终执行结果,用户表和日志表都没有添加任何数据。
执行流程描述:
- UserController 中调用了 UserService 的添加用户方法,UserService 使用 NESTED 循环嵌套事务,并成功执行了添加用户的方法。
- UserService 中调用了 LogService 的添加方法,LogService 使用了 NESTED 循环嵌套事务,但在方法执行中出现的异常,因此回滚了当前事务。
- 因为 UserService 使用的是嵌套事务,所以发生回滚的事务是全局的,也就是说 UserService 中的添加用户方法也被回滚了,最终执行结果是用户表和日志表都没有添加任何数据。
总结
Spring 事务传播机制是包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。事务的传播级别有 7 个,支持当前事务的:REQUIRED、SUPPORTS、MANDATORY;不支持当前事务的:REQUIRES_NEW、NOT_SUPPORTED、NEVER,以及嵌套事务 NESTED,其中 REQUIRED 是默认的事务传播级别。
是非审之于己,毁誉听之于人,得失安之于数。
公众号:Java面试真题解析
面试突击87:说一下 Spring 事务传播机制?的更多相关文章
- spring事务传播机制实例讲解
http://kingj.iteye.com/blog/1680350 spring事务传播机制实例讲解 博客分类: spring java历险 天温习spring的事务处理机制,总结 ...
- Spring事务传播机制和数据库隔离级别
Spring事务传播机制和数据库隔离级别 转载 2010年06月26日 10:52:00 标签: spring / 数据库 / exception / token / transactions / s ...
- spring 事务传播机制
spring 事务 传播机制 描述的 事务方法直接相互调用,父子事物开启,挂起,回滚 等的处理方式. 绿色的 那几个 我认为比较重要. 1 , @Transactional(propagation=P ...
- Spring事务传播机制与隔离级别(转)
Spring事务传播机制与隔离级别 博客分类: Spring 转自:http://blog.csdn.net/edward0830ly/article/details/7569954 (写的不错) ...
- Spring事务传播机制
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...
- spring事务传播机制的测试结果
/** * @Component是个一般性的注解,使用此注解修饰的POJO类,有value属性,指定bean的id.也可不写.默认值是类名首字母小写 * @Resource是控制依赖注 ...
- 18个示例详解 Spring 事务传播机制(附测试源码)
什么是事务传播机制 事务的传播机制,顾名思义就是多个事务方法之间调用,事务如何在这些方法之间传播. 举个例子,方法 A 是一个事务的方法,方法 A 执行的时候调用了方法 B,此时方法 B 有无事务以及 ...
- Spring事务传播机制&隔离级别
一.Propagation (事务的传播属性) Propagation : key属性确定代理应该给哪个方法增加事务行为.这样的属性最重要的部份是传播行为.有以下选项可供使用:PROPAGATION_ ...
- spring事务传播机制与隔离级别、通知类别
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为, 它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播: 事务传播行为类型 说明 PROPAGATIO ...
随机推荐
- day08 集合API | 遍历_ | 泛型 |增强For循环
集合(续) 集合间的操作 集合提供了如取并集,删交集,判断包含子集等操作 package collection; import java.util.ArrayList; import java.uti ...
- Solution -「构造」专练
记录全思路过程和正解分析.全思路过程很 navie,不过很下饭不是嘛.会持续更新的(应该). 「CF1521E」Nastia and a Beautiful Matrix Thought. 要把所有数 ...
- CentOS7添加swap分区
买了个云主机,只有1G内存,跑爬虫经常内存不足,于是只能添加swap来缓解: 1.官方推荐的swap大小定义 2.使用dd命令在根下创建swapfile dd if=/dev/zero of=/swa ...
- C++ 实现可变参数的三个方法
有时我们无法提前预知应该向函数传递几个实参.例如,我们想要编写代码输出程序产生的错误信息,此时最好用同一个函数实现该项功能,以便对所有错误的处理能够整齐划一.然而,错误信息的种类不同,所以调用错误输出 ...
- Blazor和Vue对比学习(进阶2.2.4):状态管理之持久化保存(2),Cookie/Session/jwt
注:本节涉及到前后端,这个系列的对比学习,还是专注在前端Vue和Blazor技术,所以就不撸码了,下面主要学习概念. 我们知道,Http是无状态协议,客户端请求服务端,认证一次后,如果再次请求,又要重 ...
- 2019国家集训队论文《整点计数》命题报告 学习笔记/Min25
\(2019\)国家集训队论文<整点计数>命题报告 学习笔记/\(Min25\) 补了个大坑 看了看提交记录,发现\(hz\)的\(xdm\)早过了... 前置知识,\(HAOI\)< ...
- Charles自动保存响应数据
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! 操作环境 win10 nexus5x c ...
- 【Maui正式版】创建可跨平台的Maui程序,以及有关依赖注入、MVVM双向绑定的实现和演示
前言:Maui终于在昨天(2022年8月9日)推送出来了.今儿就迫不及待来把玩一下先. A.我本地已有VS2022,不过版本比较老,此处选择更新.工具 -> 获取功能和更新里面,可以获取到新版本 ...
- MySQL启动报:[ERROR] The server quit without updating PID file
修改配置后MySQL启动不了,报错: [root@localhost mysql]# service mysql restart Starting MySQL...[ERROR] The server ...
- MySQL入门笔记一
MySQL应用笔记 一MySQL关系型数据库.开源,中小型公司常用类型的数据库Oracle 大型公司常用数据库 MySQL基本的命令一. 创建.删除.查看数据库(database)创建库creat ...