Spring @Transactional事务传播行为详解

news2024/11/28 4:49:59

 

目录

一、无事务情况

二、有事务情况

REQUIRED

SUPPORTS

MANDATORY

REQUIRES_NEW

NOT_SUPPORTED

NEVER

NESTED


Spring的事务传播机制用于控制在多个事务方法相互调用时事务的行为。

在复杂的业务场景中,多个事务方法之间的调用可能会导致事务的一致性,如出现数据丢失、重复提交等问题,使用事务传播机制可以避免这些问题的发生,保证事务的一致性和完整性。

Spring的事务规定了7种事务的传播级别,默认的传播机制是REQUIRED

一、无事务情况

我们先看一段代码:

public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}


public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}


public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}


public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

当我们运行testPropagationTrans方法,发现数据库是这样的

当saveChildren方法中有异常,也不会做事务回滚,其实也正常,因为我们也没加事务。

二、有事务情况

注:我们为了好理解,把testPropagationTrans叫做父方法,saveParent和saveChildren叫做子方法。

REQUIRED

REQUIRED:如果不存在事务则开启一个事务,如果存在事务则加入之前的事务,总是只有一个事务在执行。

举例:领导没饭吃,我有钱,我会自己买了自己吃;领导有的吃,会分给你一起吃。

比如我们代码如下;

public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRED)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

这样的结果很好理解,我在子方法有事务,当然只管我自己的回滚,并不管其它的,正所谓我有钱我自己买饭吃,别人我不管。

但是当你把@Transactional(propagation = Propagation.REQUIRED)放在父方法上,那么数据库里将会什么数据都没有,因为父方法有事务,子方法会加入此事务,相当于都包在里面了,所以有异常则全部回滚。

SUPPORTS

SUPPORTS:有事务则加入事务,没有事务则普通执行。

举例:领导没饭吃,我也没饭吃;领导有饭吃,我也有饭吃。

public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.SUPPORTS)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

很明显,如果父方法没有事务,那就相当于都没事务,就正常运行了。

但如果父方法有@Transactional(propagation = Propagation.REQUIRED)注解,则加入父方法事务。

MANDATORY

MANDATORY:强制有事务,没有事务则报异常。

举例:领导必须管饭,不管饭我就抛出异常。

public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.MANDATORY)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

这样系统直接抛出异常,因为父方法没有事务。

REQUIRES_NEW

REQUIRES_NEW:每次执行新开一个事务,如果当前存在事务,则把当前事务挂起。

举例:领导管饭,但我偏不要,我自己买了自己吃,如果领导不管饭,我自己也有钱买饭。

public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

结果说明,子方法自己创建了一个新的事务自己用。

如果我父方法上加了事务,这时数据库会发现什么数据都没有。

但我们再考虑一种情况,代码如下:

@Transactional(propagation = Propagation.REQUIRES)
public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
	int a = 1 / 0;
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveChildren() {
	saveChild1();
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

我们把异常代码放在父方法中,这时数据库结果发现:

这个结果是如何造成的呢?

其实当执行代码时,子方法创建了一个新的事务,并把父方法的事务挂起,所以也就是说,子事务是子事务,父事务是父事务,这是两个事务。

所以当父方法有异常时,直接回滚saveParent方法,并不影响子事务的操作。

NOT_SUPPORTED

NOT_SUPPORTED:如果当前有事务,则把事务挂起,自己不使用事务去运行数据库操作。

举例:领导管饭,分一点给你,但你太忙了,放一边不吃。

public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

看的出来,压根没使用事务。

当我在父方法上加上事务。

@Transactional(propagation = Propagation.REQUIRES)
public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

这个结果说明子方法没有事务,而且还把父事务挂起,所以父有事务,导致saveParent方法可以回滚。

NEVER

NEVER:如果当前有事务存在,则抛出异常。

举例:领导管饭,我不想吃,我抛出异常。

@Transactional(propagation = Propagation.REQUIRES)
public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NEVER)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

代码直接报错异常,因为never不允许你(父)有事务。

NESTED

NESTED:如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;如果当前没有事务,则同REQUIRED。但是如果主事务提交,则会携带子事务一起提交。

如果主事务回滚,则子事务一起回滚,相反,子事务异常,则父事务可以回滚或不回滚。

举例:领导决策不对,老板怪罪,领导带着小弟一同受罪。小弟出了差错,领导可以推卸责任,也可以承担责任。

@Transactional(propagation = Propagation.REQUIRES)
public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
	int a = 1 / 0;
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NESTED)
public void saveChildren() {
	saveChild1();
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

结果数据库什么数据都没有。因为父有事务,当父方法有异常,里面的嵌套事务要被回滚。

但如果子事务发生异常呢?

@Transactional(propagation = Propagation.REQUIRES)
public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
}

public void saveParent() {
	Stu stu = new Stu();
	stu.setName("parent");
	stu.setAge(30);
	stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NESTED)
public void saveChildren() {
	saveChild1();
	int a = 1 / 0;
	saveChild2();
}

public void saveChild1() {
	Stu stu1 = new Stu();
	stu1.setName("child-1");
	stu1.setAge(11);
	stuMapper.insert(stu1);
}

public void saveChild2() {
	Stu stu2 = new Stu();
	stu2.setName("child-2");
	stu2.setAge(22);
	stuMapper.insert(stu2);
}

结果数据库还是什么数据都没有,这是因为子事务的异常会影响到父方法。但这个是可选的,我们可以给父方法调用加异常,这样就不会影响父方法事务了,如下:

@Transactional(propagation = Propagation.REQUIRES)
public void testPropagationTrans() {
	stuService.saveParent();
	try {
		stuService.saveChildren();
	}catch (Exception e) {
		e.printStackTrace();
	}
}

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

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

相关文章

谷粒商城【renren-fast-vue】:npm install 报错

谷粒商城【renren-fast-vue】:npm install 报错 报错信息报错原因解决办法 报错信息 谷粒商城【renren-fast-vue】:npm install 报错 npm install 下载依赖的时候报错sass 版本与 node 版本不对应 报错原因 直接使用 npm 下载依赖,可能会…

RCE技巧

RCE技巧 Linux命令长度限制突破方法8个字符限制绕过过滤英文字母和数字php版本7php版本5 Linux命令长度限制突破方法 8个字符限制绕过 <?php <?php $param $_REQUEST[param]; if (strlen($param) < 8) {echo shell_exec($param); }shell_exec — 通过 shell 执行…

【大模型从入门到精通14】openAI API 构建和评估大型语言模型(LLM)应用2

这里写目录标题 评估大型语言模型&#xff08;LLM&#xff09;输出的方法构建评估标准实施评估协议利用专家比较案例研究评估客户服务聊天机器人学术文本摘要高级评估技术 评估大型语言模型&#xff08;LLM&#xff09;输出的方法 评估大型语言模型&#xff08;LLM&#xff09…

甄选范文“论软件设计方法及其应”软考高级论文系统架构设计师论文

论文真题 软件设计(Software Design,SD)根据软件需求规格说明书设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及程序流程等,形成软件的具体设计方案。软件设计把许多事物和问题按不同的层次和角度进行抽象,将问题或事物进行模块化分解,以便更容易解决…

无人机之电机篇

一、无人机使用什么类型的电动机 无人机主要使用直流无刷电机和伺服电机。 直流无刷电机通常用于无人机的推进系统&#xff0c;因为它具有强大的驱动力和高功率输出&#xff0c;能够为无人机提供足够的推力。 此外&#xff0c;直流无刷电机具有电动机启动转矩大、无刷向触点…

MTF-SFR总结/探讨

空间频率响应&#xff08;SFR&#xff09;定义 在iso12233:2000中&#xff0c;空间频率响应&#xff08;SFR&#xff09;测量被定义为通过分析倾斜黑白边缘附近的相机数据而测量的值。 图像清晰度测试方法 通过ISO12233测试图像清晰度的方法&#xff0c;一般有 TVline测试和S…

去中心化技术的崛起:探索Web3的新时代

引言&#xff1a; Web3是互联网发展的新阶段&#xff0c;它通过去中心化技术重新定义了数字世界的运作方式。这一新时代不仅带来了技术上的突破&#xff0c;也为社会互动和数据管理开辟了新的前景。本文将深入探讨Web3的核心技术、应用领域、全球影响以及面临的挑战&#xff0…

nvm的下载和使用(Windows)

NVM&#xff08;Node Version Manager&#xff09;是一个用于管理多个Node.js版本的工具&#xff0c;它允许用户在同一台机器上安装和使用多个Node.js版本。 一、NVM的基本功能 多版本支持&#xff1a;NVM允许用户在同一台机器上安装多个Node.js版本&#xff0c;方便处理不同…

极光流星大爆发

卑微仔广东持续200%含云量&#xff0c;线上观望大家分享的极光与流星共舞的神奇场景。 极光与流星相伴的瞬间&#xff0c;永远震撼于绝美的星空 开始放毒&#xff08;放图放图&#xff09;&#xff08;以下均拍摄于12日晚至13日晨这一时间段&#xff09;&#xff1a; 先驱猎光…

Qt之2048项目的介绍

文章目录 前言项目介绍项目截图技术介绍1. Qt 框架2. 界面绘制3. 用户输入4. 游戏逻辑5. 音效处理总结前言 2048 是一款流行的益智游戏,通过滑动屏幕上的数字方块,使相同的数字合并并生成更大的数字,最终目标是生成2048这个数字。本文介绍了基于 Qt 框架开发的一个 2048 游…

超声波清洗机哪个品牌好用?品质上等的超声波眼镜清洗机评选

随着科技的发展&#xff0c;超声波清洗机已经成为了人们生活中的清洁神器&#xff0c;它只需要清水便可以清洗假牙、刮胡刀、牙刷、眼镜、化妆工具等小物件&#xff0c;而且能够清洗到物件中的角落缝隙&#xff0c;在专业设备上还同时具备消毒除菌的功能&#xff0c;既能保证清…

软件检测报告的客观性与权威性如何确定

确保软件检测报告的客观性与权威性乃是软件测试进程中的关键要素&#xff0c;以下乃是若干确保报告质量与信誉的举措&#xff1a; 其一&#xff0c;拣选获认证的测试机构&#xff1a;选取具备 CMA&#xff08;中国计量认证&#xff09;以及 CNAS&#xff08;中国合格评定国家认…

AxMath保姆级安装教程(word联用)及使用TIPS

一、软件介绍 AxMath是一款数学公式编辑器软件。它提供了一个直观的界面&#xff0c;使用户可以轻松创建和编辑数学公式。AxMath支持多种数学符号、方程式、函数、矩阵等的输入和编辑&#xff0c;并提供了丰富的数学符号库和模板&#xff0c;方便用户快速创建复杂的数学公式。…

33_对bluecms v1.6进行代码审计、用代码审计三种方法分别进行实施、bluecms v1.6下载与安装、定向功能分析法

部署bluecms v1.6 靶场下载地址&#xff1a; https://wwtt.lanzn.com/b00uyckd9a 密码:2x71 访问 http://127.0.0.1/bluecms/install/ 数据库名称建议跟网站名一样 进入mysql-front查看&#xff0c;出现bluecms数据库&#xff0c;并且库中有很多表 然后访问前台&#xff1a;h…

DW_ahb_databook学习及部分AHB知识回顾

一、DW_ahb框图 Arbiter: 一次只允许一个master发起数据传输&#xff0c;同时可以选择slave Optional Internal Decoder: 通过解码系统地址总线为AHB上的从机生成外设选择。每个slave都可以指定一个起始和结束地址&#xff0c;该地址必须与1kb边界对齐。 Optional External D…

【云原生】高可用集群KEEPALIVED(理论篇)

一、高可用集群 1.1 集群类型 LB:Load Balance 负载均衡 LVS/HAProxy/nginx(http/upstream, stream/upstream)HA:High Availability 高可用集群数据库、RedisSPoF: Single Point of Failure&#xff0c;解决单点故障HPC: High Performance computing 高性能集群 1.2 系统可用…

第二十五天培训笔记

2 、在 python 中连接数据库并结合游标对数据库进行操作 前提&#xff1a;要有 python3 环境 pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple // 设置 pip3 的全 局配置&#xff0c;将默认的 Python 包索引源&#xff08; index-url &am…

Raspberry Pi Pico 2 上实现:实时机器学习(ML)音频噪音抑制功能

Arm 公司的首席软件工程师 Sandeep Mistry 为我们展示了一种全新的巧妙方法&#xff1a; 在 Raspberry Pi Pico 2 上如何将音频噪音抑制应用于麦克风输入。 机器学习&#xff08;ML&#xff09;技术彻底改变了许多软件应用程序的开发方式。应用程序开发人员现在可以为所需系统整…

【C++ 项目】负载均衡在线 OJ

文章目录 &#x1f308; 一、项目介绍&#x1f308; 二、项目源码&#x1f308; 三、项目演示⭐ 1. 前端界面展示⭐ 2. 后端界面展示 &#x1f308; 四、项目准备⭐ 1. 项目所用技术⭐ 2. 项目开发环境⭐ 3. 项目宏观结构 &#x1f308; 五、comm 公共模块⭐ 1. util.hpp 工具⭐…

【机器学习第9章——聚类】

机器学习第9章——聚类 9.聚类9.1 聚类任务9.2 性能度量9.3 距离计算9.4 原型聚类9.4.1 k均值算法9.4.2 学习向量量化(LVQ)9.4.3 高斯混合聚类 9.5 密度聚类DBSCAN算法 9.6 层次聚类9.7 kmeans手动算法实现9.8 kmeans算法运用 9.聚类 9.1 聚类任务 在“无监督学习”任务中研究…