Spring传播机制(七种)

news2024/12/23 10:10:58

一、概述

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。Propagation枚举则引用了这些类型,开发过程中我们一般直接用Propagation枚举。

1.1 Propagation源码

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);

    private final int value;

    private Propagation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

1.2、类型解析

  • Propagation.REQUIRED(默认机制):如果当前存在事务,那么就加入这个事务,不存在就新建一个事务。
  • Propagation.SUPPORTS:如果当前有事务,加入事务,如果没有则不使用事务
  • Propagation.MANDATORY:使用当前事务,如果当前没有事务,就抛出异常
  • Propagation.REQUIRES_NEW:新建新的事务,如果当前存在事务,就把当前事务挂起
  • Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,把当前事务挂起
  • Propagation.NEVER:以非事务方式执行操作,如果当前存在事务,就抛出异常
  • Propagation.NESTED:如果当前存在事务,则嵌套在事务内执行。如果当前没有事务,则执行Propagation.REQUIRED类似操作。

1.3 分类举例

参考文档:Spring事务管理中的七种传播机制及示例讲解 | 程序员小羊

传播机制解释
Propagation.NEVER非事务执行操作,存在事务,抛出异常
Propagation.MANDATORY使用当前事务,没有事务,抛出异常

代码案例:

//controller
@RestController
@RequestMapping("/op")
public class TestController {

    @Autowired
    private TestService testService;
    
    @GetMapping("/test1")
    public void test1() {
        testService.test1();
    }
    
}

//service
public interface TestService2 extends BaseService<Test> {

    void test2();

    void test3();
}

@Service
public class TestServiceImpl2 extends BaseServiceImpl<TestMapper, Test> implements TestService2 {


    @Override
    @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class)
    public void test2() {
        System.out.println("test2 存在事务 NEVER");
    }

    @Override
    public void test3() {
        System.out.println("test3 没有事务");
    }
}


public interface TestService extends BaseService<Test> {

    int insert(Test test);

    int update(Test test);


    void test1();

    void test4();
}

@Service
public class TestServiceImpl extends BaseServiceImpl<TestMapper, Test> implements TestService {

    @Autowired
    private TestService2 testService2;

    @Override
    public int insert(Test test) {
        return getBaseMapper().insert(test);
    }

    @Override
    public int update(Test test) {
        return getBaseMapper().updateById(test);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void test1() {
        System.out.println("test1 存在事务 REQUIRED");
        //如果在调用NEVER类型的时候,一定要用这种代理的方式,NEVER才会生效
        testService2.test2();
    }

    @Override
    @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
    public void test4() {
        System.out.println("test4 存在事务 MANDATORY");
        testService2.test3();
    }
}

测试结果

Propagation.NEVER

Propagation.MANDATORY

传播机制解释
Propagation.REQUIRED需要在事务中执行,外层有事务就加入,没有事务就自己创建一个事务
Propagation.REQUIRES_NEW需要在一个新的事务中执行,这个事务独立于外层的事务,互不影响

Propagation.REQUIRES_NEW案例

@Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void test5() {
        System.out.println("当前事务 REQUIRED ");
        Test test = new Test();
        test.setUserName("上海");
        test.setAddress("中国");
        getBaseMapper().insert(test);
        //test6用REQUIRES_NEW修饰,里面有异常,那么当前的事务也会回滚,如果test5有异常,test6不会受到影响
        testService2.test6();
        //当前事务进行回滚,test6内容会正常增加
        int i = 1/0;
    }


@Override
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void test6() {
        System.out.println("创建了一个新的事务");
        Test test = new Test();
        test.setUserName("广州");
        test.setAddress("中国");
        getBaseMapper().insert(test);

    }

注意点:

REQUIRES_NEW如果在内层,它里面的事务独立于外层的事务,外层事务如果发送异常回滚跟REQUIRES_NEW里面内容无关,如果REQUIRES_NEW里面内容回滚,那么外层的事务也会跟着回滚。

Propagation.REQUIRES_NEW测试结果

传播机制解释
Propagation.SUPPORTS外层有事务就加入,如果没有事务,就以非事务方式执行
Propagation.NOT_SUPPORTED以非事务的方式执行,执行的时候,先将外层的事务挂起,允许外层有事务。

传播机制解释
Propagation.NESTED        嵌套事务,它是已经存在事务的真正子事务,嵌套事务开始执行时,会取得一个保存点(savepoint),如果这个嵌套事务失败,将会回滚导这个保存点(savepoint),而不是整个事务的回滚

@Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void test7() {
        System.out.println("当前事务 REQUIRED ");
        Test test = new Test();
        test.setUserName("上海");
        test.setAddress("中国");
        getBaseMapper().insert(test);
        //NESTED事务如果进行回滚,但是不会对它外层的事务造成影响
        try{
            testService2.test8();
        }catch (Exception e){
            
        }
    }

  @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void test8() {
        System.out.println("创建了一个新的子事务");
        Test test = new Test();
        test.setUserName("广州");
        test.setAddress("中国");
        getBaseMapper().insert(test);
        int i = 1/0;
    }

二、总结

2.1 REQUIRED,REQUIRES_NEW,NESTED

状态REQUIRES_NEW(两个独立事务)NESTED(B事务嵌套在A事务中)REQUIRED同一个事务
A异常B正常A回滚,B正常提交A与B一起回滚A与B一起回滚
A正常B异常B先回滚,A正常提交B先回滚,A再正常提交A与B一起回滚
A正常B正常B先提交,A再提交A与B一起提交A与B一起提交

2.2 三者不同

参考文档:Spring嵌套事务异常Transaction rolled back because it has been marked as rollback-only_spring事务嵌套异常处理_Black·Tea的博客-CSDN博客

REQUIRED

  • 假设在A⽅法存在⼀个当前事务,B⽅法的事务传播机制为REQUIRED,则B⽅法会合并到A⽅法的事务⾥执⾏。
  • A、B任意⼀个⽅法异常(默认是RuntimeException和Error)都会导致A、B的操作被回滚。
  • Spring事务管理器不会吞异常。
  • B异常后会抛给A,A如果没有catch这个异常,会继续向上抛。如果A catch住了,Spring事务管理器会替A向上抛⼀个
  • UnexpectedRollbackException。总之,⼀旦A、B回滚,A的调⽤⽅⼀定能收到⼀个异常感知到回滚。(问题所在)

REQUIRES_NEW

  • 如果B发⽣异常,B事务⼀定回滚,B的异常随后会抛给A,如果A catch住了这个异常,A不会回滚,否则A也会回滚。
  • 如果A发⽣异常,则只会回滚A,不会回滚B。

NESTED

  • 如果B异常,B⼀定回滚,B的异常随后会抛给A,如果A catch住了这个异常,A不会回滚,否则A也会回滚。这种情况和REQUIRES_NEW⼀样。
  • 如果A发⽣异常,则A、B都会回滚。

2.3 手动回滚

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void test7() {
        System.out.println("当前事务 REQUIRED ");
        Test test = new Test();
        test.setUserName("上海");
        test.setAddress("中国");
        getBaseMapper().insert(test);
        //NESTED事务如果进行回滚,但是不会对它外层的事务造成影响
        try{
            testService2.test8();
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/555896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis源码浅析-ziplist实现

redis中的list是有多种实现的&#xff0c;其中一种是ziplist&#xff0c;其介绍如下 ziplist 是一个经过特殊编码的双向链表&#xff0c;旨在提高内存效率。 它存储字符串和整数值&#xff0c;其中整数被编码为实际整数而不是一系列字符。 它允许在 O(1) 时间内在列表的任一侧进…

戴尔 Dell Latitude E7480电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件配置 硬件型号驱动情况 主板戴尔 Dell Latitude E7480 处理器Intel Core i7-7700U已驱动 内存8GB 2133MHz DDR4 * 2已驱动 硬盘Sandisk 1T M.2 NVMe SSD已驱动 显…

windows解决python安装django架构没有django-admin命令

目录 一.尝试安装与配置 1.直接pip命令安装 2.用pycharm测试 3.官网下包安装 二.解决 1.找到django安装的路径 2.配置系统变量 3.测试创建项目 3.1.执行访问页面 3.2.解决 3.3.继续测试 4.pycharm打开 一.尝试安装与配置 1.直接pip命令安装 pip install django dja…

chatgpt赋能Python-python_7

Python 7 - 探索最受欢迎的Python版本 如果你是一位Python开发人员&#xff0c;你就会知道Python 7是什么。Python 7是Python编程语言的第7个主要版本&#xff0c;它带来了许多新的功能和改进&#xff0c;包括内置类型注释、上下文变量、字节码优化和更多。 在本文中&#xf…

度小满科技金融迭代:普惠小微与技术创新并肩而行

2015年&#xff0c;深度贫困乡镇隘口镇推出“本土人才”政策,呼吁大学生人才下基层,助力乡村经济振兴工作。 叶茂的人生轨迹因此而发生改变。彼时&#xff0c;20多岁的叶茂果断辞去药材公司的高薪工作&#xff0c;开始了回乡种植黄精的创业路&#xff0c;并成功竞选东坪村村主任…

log4cpp的安装(vs/visual studio版)

log4cpp安装下载源visual studio安装方法 log4cpp安装 下载源 log4cpp visual studio安装方法 将下载好的压缩包解压缩后得到下列目录&#xff08;解压缩的文件夹最好放C盘&#xff0c;不然在编译阶段往往会出现链接不上的问题&#xff09; 找到mscv10文件夹内的mscv10.sl…

【概念篇】浅谈 AOP、OOP、DDD、IOC

前言 在招聘要求中&#xff0c;有没有经常看见&#xff0c;对AOP、OOP、DDD、IOC有一定的认识&#xff0c;能够自主开发模块&#xff0c;这一类的要求。听起来是不是挺高大上&#xff0c;然后百度一搜&#xff0c;给你出来一堆概念性的东西——结果就是&#xff0c;东西…

《LKD3粗读笔记》(14)块I/O层

什么是块设备&#xff1f; 系统中能够随机访问固定大小数据片的设备被称为块设备&#xff0c;这些数据片称作块&#xff0c;最常见的块设备是硬盘。什么是字符设备&#xff1f; 字符设备按照字符流的方法被有序访问&#xff0c;像串口和键盘就都属于字符设备。这两种设备的区别…

从零开始搭建 Lsky Pro 兰空图床

本文源码&#xff1a;https://github.com/chen2438/chenhaotian.top/tree/main/source/_posts/linux-app/lsky.md 在我的博客上查看&#xff1a;https://chenhaotian.top/2022/12/30/linux-app/lsky/ 从零开始搭建 Lsky Pro 兰空图床 官方教程 安装环境 使用OneinStack安装…

第五章 面向对象-8.enum 枚举

enum 枚举 枚举的实例对象是固定的&#xff0c;实例是自动new&#xff0c;每个枚举类会自动继承java.lang.Enum 抽象类 如何声明枚举&#xff1f; 所有枚举类都是java.lang.Enum的子类&#xff0c;无需用extends来继承&#xff0c;如下是枚举类拥有的常用方法 方法名称说明…

测试报告框架 —— Allure2测试报告

目录 Allure2测试报告 1、使用 Allure2 运行方式-Python 2、使用 Allure2 运行方式-Java 3、生成测试报告 4、Allure2 报告中添加用例标题 5、allure2报告中添加用例步骤 6、allure2报告中添加用例链接 7、allure2报告中添加用例分类 8、Allure2 报告中添加用例描述 …

【面试题】前端必修-浏览器的渲染原理

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 1.浏览器的渲染原理 #浏览器是如何渲染页面的 1.什么叫渲染 render 当我们输入一个url地址的…

新书上市 | 从大脑认知开始,全方面提高编程能力,助你摆脱“GPT焦虑症”

目录 一、ChatGPT火爆全网二、《程序员超强大脑》三、本书内容四、本书特色五、作译者简介1、费莉安赫尔曼斯&#xff08;Felienne Hermans&#xff09;2、蒋楠 大家好&#xff0c;我是哪吒。 &#x1f3c6;本文收录于&#xff0c;49天精通Java从入门到就业。 全网最细Java零…

程序人生-Hello’s P2P

摘要 本文讨论了与编程和软件开发相关的几个关键概念和过程。首先介绍了链接的概念和作用&#xff0c;它是将代码和数据片段组合成单一文件的过程&#xff0c;使得分离编译成为可能&#xff0c;从而可以更好地管理和修改模块。接下来探讨了进程的概念和作用&#xff0c;进程是正…

图像数据处理

文章目录 1&#xff1a;TFRecords1-1 将MNIST数据集转换成TFRecord格式1-2 读取TFRecord文件中的数据 2&#xff1a;图像数据的预处理2-1 处理图像编码2-2 调整图像大小2-3 剪裁和填充2-4 按比例剪裁2-5 图像翻转2-6 图像亮度调整2-7 图像对比度调整2-8 图像色相调整2-9 图像饱…

chatgpt赋能Python-python_99乘法

Python编程实现——99乘法表的生成 Python编程语言是一种高级程序设计语言&#xff0c;具有简单易学、可移植性强、功能强大等特点&#xff0c;受到广大开发者的喜爱。Python可以被应用于网站开发、数据分析、人工智能、机器学习等多个领域。而在Python编程中&#xff0c;生成…

《程序员面试金典(第6版)》面试题 02.06. 回文链表(双指针(快慢指针),查找链表中间节点,反转链表)

题目描述 编写一个函数&#xff0c;检查输入的链表是否是回文的。 题目传送门~&#xff1a;面试题 02.06. 回文链表 示例 1&#xff1a; 输入&#xff1a; 1->2 输出&#xff1a; false 示例 2&#xff1a; 输入&#xff1a; 1->2->2->1 输出&#xff1a; true 进…

蓝桥杯单片机串口通信学习提升笔记——部分2

今日继续学习提升蓝桥杯国赛能力水平。 有道是&#xff1a;卜心事、灯花无语&#xff0c;百感孤单&#xff0c;鸳被羞展...... 梦方圆&#xff0c;又丛钟、声声惊断。 诗人杨玉衔孤单影只&#xff0c;偏偏又多遭磨难&#xff0c;一路坎坷...... 正如我近日来学习提升串口通信…

数据结构学习分享之链式二叉树(一)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:数据结构学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你了解更多数据结构的知识   &#x1f51d;&#x1f51d; 1. 前言 在学习链式二叉树…

【Linux】shell编程—awk编辑器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、awk编辑器1.工作流程3.常用选项 二、awk的基础用法1.输出文件中的某一列2.根据特定条件筛选数据3.按照分隔符进行切割4.在匹配到特定字符串时执行操作5.BEGIN打…