Spring事务传播行为总结
创始人
2025-05-28 02:26:10
0

Spring事务传播行为总结


1、概念

事务传播行为(propagation behavior):指的就是当一个事务方法被另一个事务方法调用时,这个事务与事务应该如何运行。
事务传播行为是Spring框架独有的事务增强特性。这是Spring为我们提供的强大的工具箱,使用事务传播行为可以为我们的开发工作提供许多便利。


2、Spring的七种事务传播行为类型

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为:

事务注解源码枚举:
在这里插入图片描述

总结:

事务传播行为类型对应说明验证结果
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。(spring 默认的类型)外围方法未开启事务:内部方法各自执行,走各自的事务,互不影响;在外围方法开启事务的情况下,内部方法会加入到外围方法的事务中,所有内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。外围开启SUPPORTS,且内部也是SUPPORTS情况下,相当于没有事务;外围开启SUPPORTS,内部方法开启别的事务,内部方法按开启的事务类型执行,互不影响;
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。外围方法开启MANDATORY事务或者没有开启事务,不管内部方法任何事务类型或者内部方法均不开启事务,都会抛出异常;外围开启别的事务,内部方法会加入到外围方法的事务中一起执行
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。内部方法声明REQUIRES_NEW类型后会新建独立事务执行,与外围方法不走同一个事务,内部方法之间事务互不影响
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。内部方法声明后就是以非事务执行,外围方法对其try catch的情况下,内部方法的异常不会导致外围方法回滚
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。以非事务执行,如果加入到的外围方法中包含事务就会报错
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。外围方法在对内部方法try catch的情况下,内部子事务可以单独回滚而不影响外围主事务和其他子事务

3、各种行为类型及对应的结果验证

声明:
user方法 person方法 为不同的两个表的方法,外围方法同时调用 user 和 person;

user方法:

    @Overridepublic void addUser(User user) {userMapper.addUser(user);}

person方法:

    @Overridepublic void addPerson(Person person) {personMapper.addPerson(person);}

person含异常方法:

    @Overridepublic void addPersonException(Person person) {personMapper.addPerson(person);int i = 1/0;}

3.1、PROPAGATION_REQUIRED类型

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)

场景3.1.1:外围方法不开启事务,User方法,Person方法均开启事务,且外围方法包含异常

外围方法:

    public void noTransactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPerson(person);//异常int i = 1/0;}

运行结果:

user表插入成功:
在这里插入图片描述

person表插入成功:
在这里插入图片描述


场景3.1.2:外围方法不开启事务,User方法,Person方法均开启事务,且Person方法包含异常

外围方法:

    public void noTransactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPersonException(person);}

运行结果:

user表插入成功:
在这里插入图片描述

person表插入失败:
在这里插入图片描述


场景3.1.3 外围方法开启事务,User方法,Person方法均开启事务,且外围方法包含异常

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPerson(person);//异常int i = 1/0;}

运行结果:

user表插入失败:
在这里插入图片描述
person表插入失败:
在这里插入图片描述


场景3.1.4 外围方法开启事务,User方法,Person方法均开启事务,且Person方法包含异常

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPersonException(person);}

运行结果:

user表插入失败:
在这里插入图片描述

person表插入失败:
在这里插入图片描述


场景3.1.5 外围方法开启事务,User方法,Person方法均开启事务,且Person方法包含的异常被try catch捕获

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");try{personService.addPersonException(person);}catch (Exception e){System.out.println("捕获person异常方法!");}}

运行结果:

user表插入失败:
在这里插入图片描述

person表插入失败:
在这里插入图片描述


PROPAGATION_REQUIRED类型事务总结:

对应场景外围是否开启事务外围方法是否包含异常外围是否捕获异常person方法是否包含异常最终执行结果
3.1.1×××均成功
3.1.2×××user成功,person失败
3.1.3××均失败
3.1.4××均失败
3.1.5捕获person的异常均失败

PROPAGATION_REQUIRED类型事务结论:
在外围方法开启事务的情况下,内部方法会加入到外围方法的事务中,所有内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。


3.2 PROPAGATION_SUPPORTS类型

@Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)

PROPAGATION_SUPPORTS类型事务总结:

经验证:
外围开启SUPPORTS,且内部也是SUPPORTS情况下,相当于没有事务;
外围开启SUPPORTS,内部方法开启别的事务,内部方法按开启的事务类型执行,互不影响;


3.3 PROPAGATION_MANDATORY类型

@Transactional(propagation = Propagation.MANDATORY,rollbackFor = Exception.class)

  1. 如果外围方法和内部方法,均开启MANDATORY,则会报以下异常;
  2. 外围开启MANDATORY,内部其中一个开启SUPPORTS类型,另一个开启REQUIRED类型也会报以下异常,因为SUPPORTS默认就是无事务;
  3. 外围开启MANDATORY,内部均开启REQUIRED类型,也会抛如下异常;
  4. 外围开启MANDATORY,内部均不开启事务,也是抛如下异常;
  5. 外围开启别的事务,则内部方法都会加入到外围的事务中一起执行;
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:362) ~[spring-tx-5.2.6.RELEASE.jar:5.2.6.RELEASE]at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:572) ~[spring-tx-5.2.6.RELEASE.jar:5.2.6.RELEASE]at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:360) ~[spring-tx-5.2.6.RELEASE.jar:5.2.6.RELEASE]at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.6.RELEASE.jar:5.2.6.RELEASE]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]

3.4 PROPAGATION_REQUIRES_NEW类型

3.4.1 外围不开启事务,user,person方法均开启REQUIRES_NEW类型事务,且外围方法有异常

外围方法:

    @Overridepublic void noTransactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPerson(person);//异常int i = 1/0;}

运行结果:

user表插入成功:
在这里插入图片描述
person表插入成功:

在这里插入图片描述


3.4.2 外围不开启事务,user,person方法均开启REQUIRES_NEW类型事务,且person方法有异常

外围方法:

    @Overridepublic void noTransactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPersonException(person);}

运行结果:

user表插入成功:
在这里插入图片描述
person表插入失败:

在这里插入图片描述


3.4.3 外围开启REQUIRED事务,user,person方法均开启REQUIRES_NEW类型事务,且外围方法有异常

外围代码:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("addPerson1");personService.addPerson(person);//异常int i = 1/0;}

运行结果:

user表插入成功:
在这里插入图片描述
person表插入成功:
在这里插入图片描述


3.4.4 外围开启REQUIRED事务,addPersonRequired方法开启REQUIRED事务,addPersonRequiredNew开启REQUIRES_NEW事务,且外围方法有异常

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {Person person1 = new Person();person1.setId(1);person1.setName("第一人");personService.addPersonRequired(person1);Person person2 = new Person();person2.setId(2);person2.setName("第二人");personService.addPersonRequiredNew(person2);Person person3 = new Person();person3.setId(3);person3.setName("第三人");personService.addPersonRequiredNew(person3);//异常int i= 1/0;}

运行结果:

第一条插入失败,其他成功

在这里插入图片描述

3.4.5 外围开启REQUIRED事务,addPersonRequired方法开启REQUIRED事务,addPersonRequiredNew开启REQUIRES_NEW事务,addPersonExceptionRequiredNew方法开启REQUIRES_NEW事务且有异常

外围代码:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {Person person1 = new Person();person1.setId(1);person1.setName("第一人");personService.addPersonRequired(person1);Person person2 = new Person();person2.setId(2);person2.setName("第二人");personService.addPersonRequiredNew(person2);Person person3 = new Person();person3.setId(3);person3.setName("第三人");personService.addPersonExceptionRequiredNew(person3);}

运行结果:

第二条成功,其他失败

在这里插入图片描述


3.4.6 外围开启REQUIRED事务,addPersonRequired方法开启REQUIRED事务,addPersonRequiredNew开启REQUIRES_NEW事务,addPersonExceptionRequiredNew方法开启REQUIRES_NEW事务且有异常,被try catch

外围代码:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {Person person1 = new Person();person1.setId(1);person1.setName("第一人");personService.addPersonRequired(person1);Person person2 = new Person();person2.setId(2);person2.setName("第二人");personService.addPersonRequiredNew(person2);Person person3 = new Person();person3.setId(3);person3.setName("第三人");try{personService.addPersonExceptionRequiredNew(person3);}catch (Exception e){System.out.println("存入第三人异常!");}}

运行结果:

第三条失败,其他成功

在这里插入图片描述


PROPAGATION_REQUIRES_NEW类型事务总结:

对应场景外围方法是否开启事务及事务类型内部方法事务类型是否有异常最终执行结果
3.4.1×均为REQUIRES_NEW外围方法包含异常均成功
3.4.2×均为REQUIRES_NEW内部person方法包含异常user成功,person失败
3.4.3REQUIRED均为REQUIRES_NEW外围方法包含异常均成功
3.4.4REQUIRED1为REQUIRED, 2 3为REQUIRES_NEW外围方法包含异常1失败,2 3成功
3.4.5REQUIRED1为REQUIRED, 2 3为REQUIRES_NEW3方法包含异常2成功,1 3失败
3.4.6REQUIRED1为REQUIRED, 2 3为REQUIRES_NEW3方法包含异常且在外围方法中被try catch3失败,1 2成功

PROPAGATION_REQUIRES_NEW类型事务结论:

(1) 3.4.1,3.4.2和3.4.3说明:
REQUIRES_NEW类型修复的方法会新建事务,内部方法的事务各自执行,互不影响,且内部方法事务不会加入到外围方法事务;

(2) 3.4.4说明:
外围REQUIRED 1为REQUIRED ,所以1和外围方法会在同一个事务,外围方法有异常,所以1必然会回滚,2 3为REQUIRES_NEW,所以2 3会各自建立新的事务,不加入到外围方法事务,所以2 3成功;

(3) 3.4.5说明:
2 3为REQUIRES_NEW会新建事务,虽然不加到外围事务,但是外围是REQUIRED,内部的事务执行异常会传导到外围方法,外围方法发现异常直接回滚,3本身又包含异常,所以3失败,导致外围失败,1方法加入外围事务,所以1也失败,2是内部新建的独立事务,所以成功;

(4) 3.4.6说明:
2 3是独立新建事务,而3有异常,所以2会成功,3失败;而3的异常被外围方法捕获,所以外围不会回滚,正常执行,所以加入到外围事务的1也会成功;


3.5 PROPAGATION_NOT_SUPPORTED类型事务


3.6 PROPAGATION_NEVER类型事务


3.7 PROPAGATION_NESTED类型事务

3.7.1 外围不开启事务,user,person方法均开启NESTED类型事务,且外围方法有异常

外围代码:

    @Overridepublic void noTransactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("person");personService.addPerson(person);int i = 1/0;}

执行结果:

user表插入成功:

在这里插入图片描述
person表插入成功:

在这里插入图片描述


3.7.2 外围不开启事务,user,person方法均开启NESTED类型事务,且person方法有异常

外围方法:

    @Overridepublic void noTransactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("person");personService.addPersonException(person);}

执行结果:
user表插入成功:

在这里插入图片描述
person表插入失败:

在这里插入图片描述


3.7.3 外围开启REQUIRED类型事务,user,person方法均开启NESTED类型事务,且外围方法有异常

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("person");personService.addPerson(person);int i = 1/0;}

运行结果:

user表插入失败:

在这里插入图片描述
person表插入失败:

在这里插入图片描述


3.7.4 外围开启REQUIRED类型事务,user,person方法均开启NESTED类型事务,且person方法有异常

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("person");personService.addPersonException(person);}

运行结果:

user表插入失败:

在这里插入图片描述
person表插入失败:

在这里插入图片描述


3.7.5 外围开启REQUIRED类型事务,user,person方法均开启NESTED类型事务,且person方法有异常在外围方法中捕获

外围方法:

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)@Overridepublic void transactional() {User user = new User();user.setId(1);user.setName("addUser1");user.setPwd("123456");userService.addUser(user);Person person = new Person();person.setId(1);person.setName("person");try{personService.addPersonException(person);}catch (Exception e){System.out.println("异常捕获!");}}

运行结果:

user表插入成功:

在这里插入图片描述
person表插入失败:

在这里插入图片描述


PROPAGATION_NESTED类型事务总结:

对应场景外围方法是否开启事务内部方法事务类型是否包含异常最终执行结果
3.7.1×NESTED类型外围方法包含异常均成功
3.7.2×NESTED类型person包含异常user成功,person失败
3.7.3REQUIREDNESTED类型外围方法包含异常均失败
3.7.4REQUIREDNESTED类型person包含异常均失败
3.7.5REQUIREDNESTED类型person包含异常且在外围方法捕获user成功,person失败

结论:
(1)在外围方法未开启事务的情况下NESTEDREQUIRED作用相同,修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
(2)在外围方法开启REQUIRED事务的情况下,NESTED修饰的内部方法属于外部事务的子事务,外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务,这是与REQUIRED的区别;


4. 关于REQUIRED,REQUIRES_NEW,NESTED异同

  1. NESTEDREQUIRED 修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回

滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法

事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方

法的事务。

  1. NESTEDREQUIRES_NEW 都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事

务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部

事务和外围事务是两个事务,外围事务回滚不会影响内部事务。


5. 事务传播特性的应用场景

如: 系统在用户注册账号会赠送积分。

那我们是期望注册成功,才会赠送积分,注册失败的话,赠送的积分也要回滚;但是积分赠送失败,不能影响注册的执行流程;另外,假设我们要记录日志,那我们期望不管注册,还是赠送积分是否有异常,都不要回滚日志;

那结合事务传播特性,我们可以这样写:

注册方法:

        @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)public void register(User user){//省略...       try {//添加积分pointService.addPoint(Point point);} catch (Exception e) {//省略...}//省略...}

添加积分方法:

        @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)public void addPoint(Point point){//省略...     try {recordService.addLog(Record record);} catch (Exception e) {//省略...}//省略...}//省略...

记录日志方法:

        @Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = Exception.class)public void addLog(Record record){//省略...}



相关内容

热门资讯

Seata架构篇 - SAGA... SAGA模式 Saga 模式是 Seata 提供的长事务解决方案,在 Saga 模式中...
【springboot】异常处... 8、异常处理 1、错误处理 1、默认规则 默认情况下,Spring Boot提供/e...
Python自动化抖音自动刷视... 环境准备 Python3.5以上Appium Server服务器Android SDK,...
libcurl库简介 一、libcurl简介libcurl是一个跨平台的网络协议库,支持http, http...
数据库存储与索引技术(三)LS... 我们在前文介绍过,多款分布式数据库都使用了LSM树作为底层的存储引擎,其...
[图神经网络]图结构和图的表示 一、图结构         图:描述关联数据的通用语言。在图中,节点之间...
三元:一泓温泉 “泡” 出康养... 日前,上海市总工会最新推出135家“2025年上海提升职工生活品质休假体验点”,三钢万寿岩学院职工疗...
PTA:C课程设计(3) 山东大学(威海)2022级大一下C习题集(3)...
LSTM从入门到精通(形象的图... 先附上这篇文章的一个思维导图什么是RNN按照八股文来说:RNN实际上就是一个带有记忆的...
推荐系统简介+算法详解+项目介... 目录标题推荐系统简介1、推荐系统目的2、推荐系统的应用3、推荐系统的基本思想4、推荐系统的数据分析5...
redhat官网相关信息链接(... Red Hat Enterprise Linux Red Hat Enterprise Linux ...
智慧水务一体化平台建设(解决方... 平台概述柳林智慧水务一体化平台是以物联感知技术、大数据、智能控制、云计算、人工智能、数字孪生、AI算...
白平衡,颜色校正,颜色映射Wh... 文章目录一,When Color Constancy Goes Wrong: Corr...
一碗面粉,五克酵母,一勺白糖,... 很久没有吃烙饼,突然有点想念,我是一个说干就干的人,立马就开始发面制作,因我平时不喜欢喝牛奶,所以发...
白炭黑硅膏制作指南解析工艺与用... 白炭黑硅膏是一种具有广泛应用前景的特殊材料,其制作过程需要一系列精细工艺。本文将深入探讨白炭黑硅膏的...
原创 夏... 高温肆虐的夏天,孩子蔫蔫的没精神?稍不留神窜稀跑肚?别担心,厨房里藏着天然的守护小能手!它们营养丰富...
Ubuntu20.04LTS部... 文章目录1.在服务器上安装jupyterlab、jupyter_server2.服务器端配置jupy...
如何突破卫星影像建模难点?重建... 日前,由重建大师生成的首个“珞珈三号01星”卫星影像三维模型一经发出,引...
王海庭:带你攀登金祖峰 在山顶... 小兴安岭的深夜,静谧,深邃。 位于伊春市的金祖峰已经亮起了光,不少登山客来到山脚下,他们整装待发,准...
【调优】Linux优化Swap... 【调优】Linux优化Swap设置 1 通过free -h查询到 free -h 内存还剩余很多...