Spring事务传播中嵌套调用实现方法详细介绍
作者:宏远十一冠王 发布时间:2021-08-31 22:34:24
前言
最近在使用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类中,如果一个非事务方法调用一个带事务的方法和事务方法之间的相互调用都不会开启新的事务。
来源:https://blog.csdn.net/zly03/article/details/126330563


猜你喜欢
- 前言quarkus号称超音速亚原子JAVA为Graalvm量身定制的java堆栈,是否名副其实呢?下面就来看看真实情况如何。动手前先简单介绍
- MyBatis Xml映射文件字符串替换字符串替换默认情况下,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStat
- 本文实例为大家分享了C# Winform实现圆角无锯齿按钮的具体代码,供大家参考,具体内容如下发现用Winform做一个圆角按钮遇到麻烦,主
- 一、JTA组件简介什么是JTAJTA,全称:Java Transaction API。JTA事务比JDBC事务更强大。一个JTA事务可以有多
- 本文实例为大家分享了Android实现支付宝记账饼图,点击旋转到最下面,供大家参考,具体内容如下代码:package com.example
- Android的主线程中执行长时间操作,导致界面无响应,会引起ANR。如果需要执行较长时间的操作,一般会在另一个线程处理,然后将数据转交给主
- Java 线程类也是一个 object 类,它的实例都继承自 java.lang.Thread 或其子类。 可以用如下方式用 java 中创
- 最近项目做完了,有闲暇时间,一直想做一个类似微信中微信发说说,既能实现拍照,选图库,多图案上传的案例,目前好多App都有类似微信朋友圈的功能
- 前言本文介绍在spring mvc中非常重要的注解@ModelAttribute.这个注解可以用在方法参数上,或是方法声明上。这个注解的主要
- 集合定义集合,集合是java中提供的一种容器,可以用来存储多个数据。特点:数组的长度是固定的。集合的长度是可变的。集合中存储的元素必须是引用
- Java File类 mkdir 不能创建多层目录File f = new File("/home/jp/Upload"
- InputStreamReader和OutputStreamWriter源码分析1. InputStreamReader 源码(基于jdk1
- RestTemplate反序列化嵌套对象假设某个接口返回的数据如下格式{ "msg" : "ok&
- 1、概念首先我们理解一下,什么叫做完美数?问题描述:若一个自然数,它所有的真因子(即除了自身以外的约数)的和恰好等于它本身,这种数叫做完全数
- 本文实例讲述了Java获取凌晨时间戳的方法。分享给大家供大家参考,具体如下:这两天有一个需求是查询用户匹配的推荐信息,包含一个有效时间段,以
- list页面的字段要求可以根据用户的喜好进行排序,所以每个用户的字段都对应着不同的顺序(字段顺序存数据库),我们从数据库里取出来的值是对象,
- Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换简单修改,完成自己想要的功能:长按,移到垃圾桶,删除数据。主
- 概述基于java + swing + JFrame 的图书馆管理系统,租车,还车,管理员管理用户,付款等。部分代码public class
- 使用enum进行定义/*枚举类型演示*/#include <stdio.h>int main() { enum /*
- 什么是Swagger?Swagger是什么:THE WORLD'S MOST POPULAR API TOOLING根据官网的介绍: