Spring事务传播机制(最全示例)
我们在使用Spring框架进行开发时,经常在service层写很多方法,而且这些方法都是带事务的,那么Spring的事务怎么在多个方法之间传播呢?今天我们就仔细聊一聊。
Spring的事务传播机制主要解决在多个方法之间,事务如何传递的问题,通常有7种传播类型:
- REQUIRED
- SUPPORTS
- MANDATORY
- REQUIRES_NEW
- NOT_SUPPORTED
- NEVER
- NESTED
下面我们就一一演示这7种类型是如何工作的。
基础代码
在讲解7种传播类型之前,我们先看看基础代码,代码很简单,大家先熟悉一下:
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
//抛出异常
int i = 1 / 0 ;
}
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
方法outerTransaction()向表中插入文本"outerTransaction",然后调用innerTransaction()方法,最后通过计算1 / 0抛出异常。
方法innerTransaction()向表中插入文本"innerTransaction",通过计算1 / 0抛出异常。
这里我们在调用innerTransaction()方法时,先获取当前的AOP代理,再通过代理调用。这是因为两个方法在同一个类中,如果不通过代理,直接调用,会脱离Spring事务AOP的管理,导致事务失效。
我们在这两个方法上使用注解,并配置不同的传播机制,通过查看数据库是否插入数据成功来演示不同传播机制的效果。
REQUIRED
REQUIRED是Spring默认的传播机制,__含义:__如果当前存在事务,则加入该事务,如果不存在事务,则创建一个事务。下面我们分别演示一下:
- 如果不存在事务,则创建一个事务。具体代码如下:
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
}
@Transactional(propagation = Propagation.REQUIRED)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
outerTransaction()方法没有事务注解,虽然调用innerTransaction()方法时有异常抛出,插入数据也应该成功。innerTransaction()方法有事务注解,传播方式为:REQUIRED,由于outerTransaction()没有事务,所以会新创建一个事务,后面有异常抛出,所以数据不会插入成功,我们测试一下,看看结果如何?

和我们的预期是一致的,innerTransaction()创建了新的事务,由于抛出异常,所以数据没有插入成功。
- 如果当前存在事务,则加入该事务,代码如下:
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
//抛出异常
int i = 1 / 0 ;
}
@Transactional(propagation = Propagation.REQUIRED)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
}
outerTransaction()增加了事务注解,传播类型为REQUIRED,由于之前没有事务,所以新创建了一个事务,然后调用innerTransaction(),innerTransaction()的传播类型也为REQUIRED,由于前面有事务,所以加入事务,最后outerTransaction()抛出异常,由于两个方法在同一个事务中,所以两个数据都不会插入成功。我们测试一下,

和我们的预期是一致的,innerTransaction()加入了outerTransaction()的事务,抛出异常后,两条数据都不会插入成功。
SUPPORTS
如果当前存在事务,则加入该事务,如果不存在事务,则以非事务的方式执行。同样我们分别演示一下。
- 如果当前存在事务,则加入该事务,代码如下:
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
//抛出异常
int i = 1 / 0 ;
}
@Transactional(propagation = Propagation.SUPPORTS)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
}
outerTransaction()是有事务的,innerTransaction()的传播类型为:SUPPORTS,则会加入到事务中,由于两个方法在同一个事务中,抛出异常后,两条数据都不会插入成功,我们测试一下,

和预期一致,没有问题。
- 如果不存在事务,则以非事务的方式执行,具体代码如下:
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
}
@Transactional(propagation = Propagation.SUPPORTS)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
我们将outerTransaction()方法的事务注解去掉,抛出异常的位置挪到innerTransaction()中,由于innerTransaction()的传播类型是SUPPORTS,外层是没有事务的,所以innerTransaction()也是没有事务的,虽然抛出了异常,但是不会回滚,两条数据都应该插入成功,我们测试一下,

和预期一致,没有问题。
MANDATORY
如果当前存在事务,则加入到事务当中;如果当前没有事务,则抛出异常。我们分别演示一下,
- 如果当前存在事务,则加入到事务当中,代码如下:
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
//抛出异常
int i = 1 / 0 ;
}
@Transactional(propagation = Propagation.MANDATORY)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
}
outerTransaction()方法是有事务的,innerTransaction()方法的传播类型是MANDATORY,会加入到事务中,由于outerTransaction()方法抛出了异常,所以两条数据都不会成功,我们测试一下,

和预期一致,都没有成功。
- 如果当前没有事务,则抛出异常,代码如下:
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
//抛出异常
int i = 1 / 0 ;
}
@Transactional(propagation = Propagation.MANDATORY)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
}
我们只是去掉了outerTransaction()上的事务注解,我们看一下会不会抛出异常,测试一下,
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
确实是抛出了异常,我们再查看一下数据库的数据,

outerTransaction()方法的数据插入成功了,因为outerTransaction()方法没有事务,虽然后面的方法抛出了异常,但数据还是会插入成功。
REQUIRES_NEW
总是创建一个新的事务,如果当前存在事务,则挂起当前事务。这句话怎么理解呢?我们看看下面的代码,
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
//抛出异常
int i = 1 / 0 ;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
}
outerTransaction()是有事务的,innerTransaction()方法的传播类型是REQUIRES_NEW,会创建一个新的事务,虽然outerTransaction()最后抛出了异常,由于两个方法是两个事务,所以异常只会对外层事务回滚,我们测试一下,

innerTransaction()插入数据成功,outerTransaction()方法由于有异常,所以进行了回滚。如果将异常从外层挪到内层,也就是外层不抛出异常,而内层抛出异常,执行结果会是什么样子呢?小伙伴们自己思考一下吧。
NOT_SUPPORTED
以非事务的方式执行操作,如果当前存在事务,则挂起当前事务。这种传播类型说明方法都是非事务的,不管外层有没有事务,我们先看看代码,
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
outerTransaction()是有事务的,innerTransaction()的传播类型是NOT_SUPPORTED,说明innerTransaction()以非事务执行,数据插入后,抛出异常,由于外层是有事务的,所以外层事务回滚,我们测试一下,

和预期是一致的,内层以非事务执行,插入数据成功,外层有事务,而且有异常,所以事务回滚。
NEVER
以非事务的方式执行操作,如果当前存在事务,则抛出异常。我们具体看一下代码,
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
}
@Transactional(propagation = Propagation.NEVER)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
outerTransaction()有事务,innerTransaction() 的传播类型是NEVER,由于外层方法有事务,所以要抛异常,外层方法也要回滚,所以两条数据都不会插入成功,我们测试一下,
抛出的异常是:
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
再看看数据库中的数据,

和预期是一致的。
NESTED
如果当前存在事务,则在当前事务中创建一个新的嵌套事务;如果当前没有事务,则创建一个新的任务。我们分别看一下是什么意思。
- 如果当前没有事务,则创建一个新的任务。这个感觉和REQUIRED是一样的,我们先看看代码,
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
currentProxy.innerTransaction();
}
@Transactional(propagation = Propagation.NESTED)
public void innerTransaction() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
outerTransaction()没有事务,innerTransaction()的传播类型是NESTED,会创建一个新的事务,由于抛出了异常所以内层会回滚,外层没有事务,会插入数据成功,我们测试一下,

和预期一致。
- 如果当前存在事务,则在当前事务中创建一个新的嵌套事务。我们再看看代码,
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
//向表中插入文本“outerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("outerTransaction");
transactionPropagationMapper.insert(tp);
//调用innerTransaction方法
TransactionPropagationService currentProxy = (TransactionPropagationService)AopContext.currentProxy();
try {
currentProxy.innerTransaction1();
currentProxy.innerTransaction2();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.NESTED)
public void innerTransaction1() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction1");
transactionPropagationMapper.insert(tp);
}
@Transactional(propagation = Propagation.NESTED)
public void innerTransaction2() {
//向表中插入文本“innerTransaction”
TransactionPropagation tp = new TransactionPropagation();
tp.setMethodName("innerTransaction2");
transactionPropagationMapper.insert(tp);
//抛出异常
int i = 1 / 0 ;
}
outerTransaction()有事务,分别调用innerTransaction1()和innerTransaction2() ,并catch异常,innerTransaction1()和innerTransaction2()的传播机制都是NESTED,会分别创建一个内嵌事务,innerTransaction1()正常结束,没有异常,innerTransaction2()抛出异常事务回滚,而外层由于catch了异常,方法也可以正常结束,所以不会回滚。我们预测的是:outerTransaction()插入成功,innerTransaction1()插入成功,innerTransaction2()回滚。我们测试一下,

和我们的预测是一致的。
总结
到此,Spring的7种传播机制就介绍完了。这里边的内容很多,是不好记忆的,其实我们也不必死记硬背,看看源码中的注释就可以了。如果再不行,就翻翻我的博客多看看吧~~
Spring事务传播机制(最全示例)的更多相关文章
- 面试突击87:说一下 Spring 事务传播机制?
Spring 事务传播机制是指,包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的. 既然是"事务传播",所以事务的数量应该在两个或两个以上,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 (写的不错) ...
- 18个示例详解 Spring 事务传播机制(附测试源码)
什么是事务传播机制 事务的传播机制,顾名思义就是多个事务方法之间调用,事务如何在这些方法之间传播. 举个例子,方法 A 是一个事务的方法,方法 A 执行的时候调用了方法 B,此时方法 B 有无事务以及 ...
- spring事务传播机制的测试结果
/** * @Component是个一般性的注解,使用此注解修饰的POJO类,有value属性,指定bean的id.也可不写.默认值是类名首字母小写 * @Resource是控制依赖注 ...
- Spring事务传播机制
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...
- Spring 事务传播机制和数据库的事务隔离级别
Propagation(事务传播属性) 类别 传播类型 说明 支持当前事务 REQUIRED 如果当前没有事务,就新建一个事务.@Transaction的默认选择 支持当前事务 SUPPORTS 就以 ...
- Spring事务传播机制&隔离级别
一.Propagation (事务的传播属性) Propagation : key属性确定代理应该给哪个方法增加事务行为.这样的属性最重要的部份是传播行为.有以下选项可供使用:PROPAGATION_ ...
随机推荐
- Asp .Net Core 系列:详解授权以及实现角色、策略、自定义三种授权和自定义响应
什么是授权(Authorization)? 在 ASP.NET Core 中,授权(Authorization)是控制对应用资源的访问的过程.它决定了哪些用户或用户组可以访问特定的资源或执行特定的操作 ...
- js实现动态表格的添加
<!DOCTYPE html> <html lang="en"> <head> <title>Table_Simple CSS fo ...
- .NET 开源快捷的数据库文档查询和生成工具
前言 在实际项目开发中,需求变更和项目迭代是常态.要求我们能够迅速响应,对数据库结构进行相应的调整,如添加新表.更新现有表结构或增加字段等. 为了确保团队成员之间的信息同步,实时更新和维护数据库文档变 ...
- centos8配置网络环境及阿里云网络yum源
一.centos8配置网络环境 1.修改配置网卡配置文件 [root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens18 TYPE ...
- 【vue3】详解单向数据流,大家千万不用为了某某而某某了。
总览 Vue3 的单向数据流 尽信官网,不如那啥. vue的版本一直在不断更新,内部实现方式也是不断的优化,官网也在不断更新. 既然一切皆在不停地发展,那么我们呢?等着官网更新还是有自己的思考? 我觉 ...
- 【H5】10 嵌入技术
到目前为止,您应该掌握了将图像.视频和音频嵌入到网页上的诀窍了. 此刻,让我们继续深入学习,来看一些能让您在网页中嵌入各种内容类型的元素: <iframe>, <embed> ...
- 【Spring Data JPA】02 快速上手
完成一个CRUD - 创建工程导入依赖坐标 - 配置Spring的配置文件 - 配置ORM的实体类,绑定映射关系 - 编写一个符合SpringDataJpa的dao接口 Maven依赖坐标 <p ...
- If Messi doesn't understand how to respect others, then he also doesn't deserve to receive respect from others.
If Messi doesn't understand how to respect others, if he doesn't understand the spirit of honoring c ...
- Gitee官网大规模封禁开源项目,如想解禁则需手动提交审核,在此过程中一些项目的信息也被gitee官方修改!!!
由于美国政府对中国的各种打压和制裁,为了支持国产软件我已经将GitHub上的大多数代码库迁移到了gitee上,虽然我的开源库基本都是个人学习时候的一些代码并不是什么成品项目代码,但是不管力量大小也都支 ...
- 基础数据结构->set&&map
set&&map BEGIN:惜墨如金 set用法 基本用法 #include<bits/stdc++.h> using namespace std; void the_s ...