前言

最近在使用Spring框架时遇到了一些问题,主要是Spring的事务传播问题,一个不带事务的方法调用带事务的方法,有时候会出现不回滚的情况,所以写了这篇文章来记录一下。

7种传播方式

我们先来看Spring事务的7中传播方式以及对应的描述

属性名称 描述
PROPAGATION__REQUIRED REQUIRED 表示的是当前这个方法必须运行在一个事务环境中,如果当前方法已经处于事务环境中,就可以直接使用该方法,否则开启一个新的事务
PROPAGATION_SUPPORTS SUPPORTS 如果当前方法处于事务环境中,就使用当前事务,否则不使用事务
PROPAGATION_MANDATORY MANDATORY 表示当前方法一定要处于事务环境中,否则就抛出异常
PROPAGATION_REQUIRES_NEW REQUIRES_NEW 当前方法需要运行在新的事务中。如果当前方法已在事务环境中,先暂停当前事务,在启动新的事务方法后才执行该方法,如果当前方法不在事务环境中,就启动一个新的事务后启动执行该方法。
PROPAGATION_NOT_SUPPORTED NOT_SUPPORTED 不支持当前的事务,总是以非事务状态执行。如果这个方法是事务方法,就先挂起这个事务方法,再执行这个方法
PROPAGATION_NEVER NEVER 不支持当前事务,如果是事务方法,则抛出异常
PROPAGATION__NESTED NESTED 如果当前执行的方法处于事务环境中,依旧会启动一个事务,嵌套的事务也可以独立于当前事务独立回滚和提交,如果当前执行的方法不在事务环境中,也会启动一个新事务。

注解式事务

在Spring中,我们常用@Transactional来标注一个事务方法,如果有点进去这个注解的源码都可以看到Spring对于添加这个注解的方法,都会默认将这个方法的事务的传播等级设置为REQUIRED,也就是是当前方法必须处于一个事务方法中,或者使用调用这个方法的事务行为。

下面我们来分析下这个注解在什么情况下会失效,并且需要怎么样来去避免这种情况的发生。

事务的方法之间的调用

下面这个例子模仿的是一个带事务的方法调用另外一个事务方法,在下面的这个方法报错,查看当前事务有没有进行回滚

@Override
@Transactional(rollbackFor = Exception.class)
public void saveWithDish(SetmealDto setmealDto){
this.save(setmealDto);
List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
}
@Transactional(rollbackFor = Exception.class)
public void saveBa(List<SetmealDish> setmealDishes, SetmealDto setmealDto) throws Exception{ setmealDishes = setmealDishes.stream().peek((item) -> item.setSetmealId(setmealDto.getId())).collect(Collectors.toList());
setmealDishService.saveBatch(setmealDishes);
int j = 2/0;
}

根据事务的传播等级来看,这种情况是肯定可以回滚的,但是如果是同一类中,像下面这种情况,同一个类中一个不带事务的方法调用另外一个带事务的方法,这种情况下它的事务会不会回滚呢?理论上我们觉得是会的,但是在测试的时候呢,我们发现这个事务并没有进行回滚,也就是说,这个事务注解@Transantional没有生效

@Override
public void saveWithDish(SetmealDto setmealDto) throws Exception{ List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes(); saveBa(setmealDishes, setmealDto);
}
@Transactional(rollbackFor = Exception.class)
public void saveBa(List<SetmealDish> setmealDishes, SetmealDto setmealDto) throws Exception{
this.save(setmealDto);
setmealDishes = setmealDishes.stream().peek((item) -> item.setSetmealId(setmealDto.getId())).collect(Collectors.toList());
setmealDishService.saveBatch(setmealDishes);
int j = 2/0; }

虽然这里我们报错了,但是数据库中还是新增了一条刚刚我们添加的一条数据,这样可以说明,这是没有添加事务的,也验证了上面我们的方法。

下面我们来看情况上,当不同类之间类方法的调用,如果一个事务方法调用一个非事务方法,这样非事务方法当然可以获取到当前这个事务的,不会开启一个新的事务。但是当一个非事务方法调用一个不同类的事务方法时,这样会不会回滚呢,答案是会的,这边我已经进行验证过了。

注意事项

我们需要记住Spring的默认事务传播等级是Required,在Spring扫描Bean时,会扫描这个方法是否带有@Transactional注解,如果是包含的话,Spring会动态生成一个代理类(proxy),当这个方法被调用时,是由代理类来进行调用的,而在初始化时,同一个类下面,这个方法如果是没有带@Transactional注解调用一个@Transactional的方法的话,这个方法的调用是没有经过代理类的,就不会启动transactional,也就是在同一个类出现无效的现象出现

所以,解决的话,我们可以将这两个方法分开到两个不同的类中,所以我们可以知道在一个service类中,如果一个非事务方法调用一个带事务的方法和事务方法之间的相互调用都不会开启新的事务。

Spring事务传播之嵌套调用的更多相关文章

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

    Spring事务传播机制回顾 Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务.结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷. 其实这 ...

  2. spring事务传播机制与隔离级别、通知类别

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

  3. spring事务传播机制实例讲解

    http://kingj.iteye.com/blog/1680350   spring事务传播机制实例讲解 博客分类:   spring java历险     天温习spring的事务处理机制,总结 ...

  4. Spring事务传播机制

    Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...

  5. spring 事务传播行为实例分析

    Spring事务传播行为: spring特有的事务传播行为,spring支持7种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的 ...

  6. Spring事务传播机制与隔离级别(转)

    Spring事务传播机制与隔离级别 博客分类: Spring   转自:http://blog.csdn.net/edward0830ly/article/details/7569954 (写的不错) ...

  7. Spring事务传播性

    事务是逻辑处理原子性的保证手段,通过使用事务控制,可以极大的避免出现逻辑处理失败导致的脏数据等问题.事务最重要的两个特性,是事务的传播级别和数据隔离级别.传播级别定义的是事务的控制范围,事务隔离级别定 ...

  8. spring 事务传播行为类型

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

  9. 理解 spring 事务传播行为与数据隔离级别

    事务,是为了保障逻辑处理的原子性.一致性.隔离性.永久性. 通过事务控制,可以避免因为逻辑处理失败而导致产生脏数据等等一系列的问题. 事务有两个重要特性: 事务的传播行为 数据隔离级别 1.事务传播行 ...

  10. spring事务传播行为讲解转载

    https://segmentfault.com/a/1190000013341344 前言 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为.事务传播行为是 ...

随机推荐

  1. day48-Mysql安装文件结构及SQL常用语句

    1.安装文件结构 bin--mysql.exe 客户端运行程序: mysqld.exe 服务端运行程序:  data--数据库.数据表等文件 注:修改配置文件后需要重启服务端 2.常用SQL语句 1) ...

  2. 修改linux服务器时间

    date -s "20220104 11:07:05" &&hwclock --systohc

  3. angularJS依赖注入的个人理解

    依赖注入:一句话 --- 没事你不要来找我,有事我会去找你. AngularJS    5个核心组件用来作为依赖注入: value factory service provider constant ...

  4. Arduino优化 减少重复代码 例2

    Example->Blink: void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUI ...

  5. insert-text-at-cursor-in-a-content-editable-div

    https://stackoverflow.com/questions/2920150/insert-text-at-cursor-in-a-content-editable-div function ...

  6. Android笔记--图形控制

    图形Drawable 形状图形(其定义文件是以shape标签为根节点的XML描述文件,支持四种类型的形状) 具体实现: 在shape标签里面,solid指定填充的颜色,stroke指定边框颜色,cor ...

  7. python爬取今日的bing壁纸

    #!/usr/bin/python #你要的文件夹是 E://pics// ps:没有的话帮你建一个 import requests import os from datetime import da ...

  8. 关于VScode vue3卡顿

    在使用vscode+volar开发vue3项目时,出现代码提示缓慢的问题.通过开启Volar Takeover *模式解决. 以下摘自Vue3官网 https://cn.vuejs.org/guide ...

  9. Python类的继承,你了解多少?

    "三人行必有我师焉!"."不耻下问",中国的圣人先师孔子留下的文化瑰宝传承在生活中的每个角落. 孔子是中国古代最伟大的思想家.教育家.如果说中国有一种根本的立国 ...

  10. EF Core如何使用DbFirst

    首先安装好 Microsoft.EntityFrameworkCore.SqlServer   [ef 的数据库驱动程序 如果是其他数据库这个要换成对应的数据库驱动] Microsoft.Entity ...