当前位置: 首页 > news >正文

Springboot事务控制中A方法调用B方法@Transactional生效与不生效情况实战总结

介绍

本篇对Springboot事务控制中A方法调用B方法@Transactional生效与不生效情况进行实战总结,让容易忘记或者困扰初学者甚至老鸟的开发者,只需要看这一篇文章即可立马找到解决方案,这就是干货的价值。喜欢的朋友别忘记来个一键三连哈:)

实战步骤

由于A方法调用B方法的情况较多,此处按照 一定的命名规则复现各种情况。
例如:

c代表class,c0代表不同类,c1代表同类
a代表a方法,a0代表a方法无事务注解,a1代表有
b代表b方法,b0代表b方法无事务注解,b1代表有
e代表抛异常,ea代表a方法中抛异常;eb代表b方法执行抛异常;

组合起来:c1a0b1ea 表示:同类中a调用b,b上有事务,a中抛异常

创建表

CREATE TABLE `tb_user`  (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,`nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 36 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

创建测试类

AbstractUserService执行事务操作

@Service
public class AbstractUserService {@Autowiredprivate UserService userService;/***  新增用户* @param username*/public void saveUser(String username) {UserEntity userEntity = new UserEntity();userEntity.setUsername(username);userService.save(userEntity);}/***  更新密码* @param username*/public void updatePassword(String username) {UserEntity entity = userService.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getUsername,username));entity.setPassword("123456");userService.updateById(entity);}/*** 制造异常*/public void makeException() {int i=1/0;}
}

Service01 代表a类

@Service
public class Service01 extends AbstractUserService{@Autowiredprivate Service02 service02;// 同类调用public void c1_a0_b1_ea(String username){saveUser(username);this.b1(username,false);makeException();}public void c1_a0_b1_eb(String username){saveUser(username);this.b1(username,true);}@Transactional(rollbackFor = Exception.class)public void c1_a1_b0_ea(String username){saveUser(username);this.b0(username,false);makeException();}@Transactional(rollbackFor = Exception.class)public void c1_a1_b0_eb(String username){saveUser(username);this.b0(username,true);}@Transactional(rollbackFor = Exception.class)public void c1_a1_b1_ea(String username){saveUser(username);this.b1(username,false);makeException();}@Transactional(rollbackFor = Exception.class)public void c1_a1_b1_eb(String username){try{saveUser(username);this.b1(username,true);}catch (Exception e){System.out.println("c1_a1_b1_eb执行失败:");throw new RuntimeException("c1_a1_b1_eb执行失败");}}// 不同类调用public void c0_a0_b1_ea(String username){saveUser(username);service02.b1(username,false);makeException();}public void c0_a0_b1_eb(String username){saveUser(username);service02.b1(username,true);}@Transactional(rollbackFor = Exception.class)public void c0_a1_b0_ea(String username){saveUser(username);service02.b0(username,false);makeException();}@Transactional(rollbackFor = Exception.class)public void c0_a1_b0_eb(String username){saveUser(username);service02.b0(username,true);}@Transactional(rollbackFor = Exception.class)public void c0_a1_b1_ea(String username){saveUser(username);service02.b1(username,false);makeException();}@Transactional(rollbackFor = Exception.class)public void c0_a1_b1_eb(String username){saveUser(username);service02.b1(username,true);}public void b0(String username,boolean hasException){updatePassword(username);if(hasException){makeException();}}@Transactional(rollbackFor = Exception.class)public void b1(String username, boolean hasException){updatePassword(username);if(hasException){makeException();}}}

Service02 代表b类

@Service
public class Service02 extends AbstractUserService{public void b0(String username,boolean hasException){updatePassword(username);if(hasException){makeException();}}@Transactional(rollbackFor = Exception.class)public void b1(String username, boolean hasException){updatePassword(username);if(hasException){makeException();}}
}

测试接口TestController

@RestController
@RequestMapping("")
public class TestController {@Autowiredprivate Service01 service01;/*** 同类* a没有事务,b有 ,异常发生在a中 不会回滚* @return*/@GetMapping("/c1_a0_b1_ea")public String test1() {service01.c1_a0_b1_ea("c1_a0_b1_ea");return "ok";}/*** 同类*  a没有事务,b有 ,异常发生在b中 不会回滚* @return*/@GetMapping("/c1_a0_b1_eb")public String test2() {service01.c1_a0_b1_eb("c1_a0_b1_eb");return "ok";}/*** 同类*  a有事务,b没有 ,异常发生在a中 会回滚* @return*/@GetMapping("/c1_a1_b0_ea")public String test3() {service01.c1_a1_b0_ea("c1_a1_b0_ea");return "ok";}/*** 同类*  a有事务,b没有 ,异常发生在b中 会回滚* @return*/@GetMapping("/c1_a1_b0_eb")public String test4() {service01.c1_a1_b0_eb("c1_a1_b0_eb");return "ok";}/*** 同类*  a有事务,b有 ,异常发生在a中 会回滚* @return*/@GetMapping("/c1_a1_b1_ea")public String test5() {service01.c1_a1_b1_ea("c1_a1_b1_ea");return "ok";}/*** 同类*  a有事务,b有 ,异常发生在b中 会回滚* @return*/@GetMapping("/c1_a1_b1_eb")public String test6() {service01.c1_a1_b1_eb("c1_a1_b1_eb");return "ok";}/*** 不同类*  a没有事务,b有 ,异常发生在a中 不会回滚* @return*/@GetMapping("/c0_a0_b1_ea")public String test7() {service01.c0_a0_b1_ea("c0_a0_b1_ea");return "ok";}/*** 不同类*  a没有事务,b有 ,异常发生在b中 只有b回滚* @return*/@GetMapping("/c0_a0_b1_eb")public String test8() {service01.c0_a0_b1_eb("c0_a0_b1_eb");return "ok";}/*** 不同类*  a有事务,b没有 ,异常发生在a中 会回滚* @return*/@GetMapping("/c0_a1_b0_ea")public String test9() {service01.c0_a1_b0_ea("c0_a1_b0_ea");return "ok";}/*** 不同类*  a有事务,b没有 ,异常发生在b中 会回滚* @return*/@GetMapping("/c0_a1_b0_eb")public String test10() {service01.c0_a1_b0_eb("c0_a1_b0_eb");return "ok";}/*** 不同类*  a有事务,b有 ,异常发生在a中 会回滚* @return*/@GetMapping("/c0_a1_b1_ea")public String test11() {service01.c0_a1_b1_ea("c0_a1_b1_ea");return "ok";}/*** 不同类*  a有事务,b有 ,异常发生在b中 会回滚* @return*/@GetMapping("/c0_a1_b1_eb")public String test12() {service01.c0_a1_b1_eb("c0_a1_b1_eb");return "ok";}
}

测试结果

http://localhost:9000/test/c0_a1_b1_eb

在浏览器中依次访问测试接口中的每个方法,得到表中结果:
以下情况未回滚或者半回滚,不在表里的均正常回滚事务。
在这里插入图片描述

原理总结

原理:
spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。
此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是@Transactional注解无效。

那回到一开始的问题,我们调用的方法A不带注解,因此代理类不开事务,而是直接调用目标对象的方法。当进入目标对象的方法后,执行的上下文已经变成目标对象本身了,因为目标对象的代码是我们自己写的,和事务没有半毛钱关系,此时你再调用带注解的方法,照样没有事务,只是一个普通的方法调用而已。
简单来说,内部调用本类方法,不会再走代理了,所以B的事务不起作用。

如果AB不同类,A调用的事代理类B,故B有事务。

参考文章

  • https://blog.csdn.net/weixin_36586564/article/details/105687331
  • https://juejin.cn/post/7031446300142862373
  • 【@Transactional注解失效的几种情况】
    https://blog.csdn.net/Yaml4/article/details/138123693

相关文章:

Springboot事务控制中A方法调用B方法@Transactional生效与不生效情况实战总结

介绍 本篇对Springboot事务控制中A方法调用B方法Transactional生效与不生效情况进行实战总结&#xff0c;让容易忘记或者困扰初学者甚至老鸟的开发者&#xff0c;只需要看这一篇文章即可立马找到解决方案&#xff0c;这就是干货的价值。喜欢的朋友别忘记来个一键三连哈&#x…...

python -【三】循环语句

一、while 循环 while 语法 while 条件: 条件满足时&#xff0c;做事情 a 0 while a < 100:print(i like python ...)a 1求 1-100 的总和 i 1 sum 0 while i < 100:sum ii 1 print(f1-100 的和是 {sum})""" 1-100 的和是 5050 ""&…...

类的内存对齐位段位图布隆过滤器哈希切割一致性哈希

文章目录 一、类的内存对齐1.1规则1.2原因 二、位段2.1介绍2.2内存分配问题2.3跨平台问题2.4使用的注意事项 三、位图的应用3.1 给40亿个不重复的无符号整数&#xff0c;找给定的一个数。&#xff08;int的范围可以到达42亿多&#xff09;3.2 给定100亿个整数&#xff0c;设计算…...

于ThinkPHP开发的赛事报名小程序

基于ThinkPHP开发的赛事报名微信小程序 功能包括 1、参赛公告 2、会员中心&#xff08;会员注册、登录、成绩查询、资料管理、参赛记录管理&#xff09; 3、个人报名和企业报名 &#xff08;身份证验证防止重复报名&#xff09; 4、培训报名 5、查询是否在库人员&#xff0c;根…...

前端学习--React部分

文章目录 前端学习--React部分前言1.React简介1.1React的特点1.2引入文件1.3JSX&#x1f349;JSX简介与使用&#x1f349;JSX语法规则 1.4模块与组件&#x1f349;模块&#x1f349;组件 1.5安装开发者工具 2.React面向组件编程2.1创建组件&#x1f349;函数式组件&#x1f349…...

24V_2A_1.2MHZ|PCD0303升压恒频LCD背光源专用电路超小体积封装

概述 PCD0303是一个恒定频率&#xff0c;6针SOT23电流模式升压转换器用于小型低功耗应用。PCD0303 以1.2MHz切换&#xff0c;并且允许使用微小的&#xff0c;低成本电容器和电感器2mm或更小,内部软启动会产生较小的涌入电流延长电池寿命。PCD0303具有自动切换至轻负载下的脉冲…...

python生成词云图

生成词云图的话需要先对数据进行分词处理 , 分词方法点击查看 import pandas as pd from collections import Counter from wordcloud import WordCloud import matplotlib.pyplot as plt# 假设您已经按照之前的步骤处理了数据&#xff0c;并且处理后的数据保存在comments_proc…...

【使用ChatGPT构建应用程序】应用程序开发概述:1. 管理秘钥、2. 数据安全、3. 与应用程序解耦、4. 注意提示语的注入攻击

文章目录 一. 首先注意的两个方面1. 管理API密钥1.1. 用户提供API密钥1.2. 你自己提供API密钥 2. 数据安全和数据隐私 二. 软件架构设计原则&#xff1a;与应用程序解耦三. 注意LLM提示语的注入攻击1. 分析输入和输出2. 监控和审计3. 其他要注意的注入情况 在了解了ChatGPT的文…...

【JavaScript脚本宇宙】不可或缺的Web开发工具:图表和可视化

图形化你的数据&#xff1a;六款顶级JavaScript库全接触 前言 在本文中&#xff0c;我们将深入探讨六个强大的JavaScript库&#xff0c;这些库被广泛应用于数据可视化和交互式图形展示。我们将了解每个库的概述、主要特性、使用示例以及使用场景&#xff0c;以帮助读者更全面…...

自然语言处理(NLP)中的迁移学习

Transfer Learning in NLP 迁移学习&#xff08;Transfer Learning&#xff09;无疑是目前深度学习中的新热点&#xff08;相对而言&#xff09;。在计算机视觉领域&#xff0c;它已经应用了一段时间&#xff0c;人们使用经过训练的模型从庞大的ImageNet数据集中学习特征&…...

PLC集成BL121PO网关优化智能电网的远程管理PLC转OPC UA协议

随着工业自动化技术的不断发展&#xff0c;智能电网等复杂系统对于设备之间高效通信的需求日益增加。PLC转OPC UA协议转换网关BL121PO作为一款领先的协议转换设备&#xff0c;通过其独特的设计和功能&#xff0c;为用户提供了高效、安全的PLC接入OPC UA的解决方案。 设备概述 …...

爬虫案例(读书网)

一.我们还是使用简单的bs4库和lxml&#xff0c;使用xpath&#xff1a; 导入下面的库&#xff1a; import requests from bs4 import BeautifulSoup from lxml import etree 我们可以看见它的div和每个书的div框架&#xff0c;这样会观察会快速提高我们的简单爬取能力。 二.实…...

Linux系统编程(五)多线程创建与退出

目录 一、基本知识点二、线程的编译三、 线程相关函数1. 线程的创建&#xff08;1&#xff09;整型的传入与接收&#xff08;2&#xff09;浮点数的传入与接收&#xff08;3&#xff09;字符串的传入与接收&#xff08;4&#xff09;结构体的传入与接收 2. 线程的退出3. 线程的…...

计算机毕业设计 | SpringBoot个人博客管理系统(附源码)

1&#xff0c;绪论 1.1 背景调研 在互联网飞速发展的今天&#xff0c;互联网已经成为人们快速获取、发布和传递信息的重要渠道&#xff0c;它在人们政治、经济、生活等各个方面发挥着重要的作用。互联网上发布信息主要是通过网站来实现的&#xff0c;获取信息也是要在互联网中…...

字母的大小写转换

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中&#xff0c;字符串对象提供了lower()方法和upper()方法进行字母的大小写转换&#xff0c;即可用于将大写字母转换为小写字母或者将小写字…...

JTW结构

JTW(JSON Web Token)的结构 在这篇笔记中,我们将了解JTW(JSON Web Token)的结构。我们将看到JTW是如何创建的,令牌的各个部分是什么,以及您如何自己构建和构造JTW。您还将了解一些这种结构的含义,以及使用JTW进行授权时的一些结果优缺点。 基本上,JTW本质上就是一个…...

debian11安装留档@VirtualBox

因为debian12无法安装tpot&#xff0c;所以又把11重新安装一遍&#xff0c;以前的安装文档&#xff1a;安装Debian 11 留档-CSDN博客 下载光盘 华为云地址&#xff1a;https://repo.huaweicloud.com/debian-cd/11.0.0/amd64/iso-cd/ 使用了debian11 教育版&#xff0c;比较有…...

SpringBoot——整合Thymeleaf模板

目录 模板引擎 新建一个SpringBoot项目 pom.xml application.properties Book BookController bookList.html ​编辑 项目总结 模板引擎 模板引擎是为了用户界面与业务数据分离而产生的&#xff0c;可以生成特定格式的页面在Java中&#xff0c;主要的模板引擎有JSP&…...

电商推荐系统+电影推荐系统【虚拟机镜像分享】

电商推荐系统电影推荐系统【虚拟机镜像分享】 所有组件部署好的镜像下载&#xff08;在下面&#xff09;&#xff0c;仅供参考学习。&#xff08;百度网盘&#xff0c;阿里云盘…&#xff09; 博主通过学习尚硅谷电商推荐电影推荐项目&#xff0c;将部署好的虚拟机打包成ovf文…...

(函数)判断素数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明素数判断函数&#xff1b; void prime(int number);int main() {//初始化变量值&#xff1b;int number 0;//获取用户输入的数据&#xff1b;printf(&quo…...

避开这些坑!医疗内窥镜Zemax优化时的高温灭菌与弯曲成像难题解决指南

医疗内窥镜光学系统设计实战&#xff1a;高温灭菌与弯曲成像的Zemax解决方案 在微创手术和工业检测领域&#xff0c;直径仅2.8mm的医疗内窥镜需要同时满足140广角视场、F2.0大光圈和10μm高分辨率的要求。更严峻的挑战来自使用环境——必须耐受135℃高温蒸汽灭菌&#xff0c;并…...

OpenClaw对话增强:nanobot模型微调提升任务理解准确率

OpenClaw对话增强&#xff1a;nanobot模型微调提升任务理解准确率 1. 为什么需要专业场景的模型微调 在测试OpenClaw基础版本时&#xff0c;我发现一个明显痛点&#xff1a;当处理专业领域的自动化任务时&#xff0c;通用大模型经常出现"理解偏差"。比如在医疗文献…...

OpenClaw多设备同步:GLM-4.7-Flash配置共享方案

OpenClaw多设备同步&#xff1a;GLM-4.7-Flash配置共享方案 1. 为什么需要多设备同步配置&#xff1f; 去年冬天&#xff0c;我在办公室和家里两台MacBook上分别部署了OpenClaw对接GLM-4.7-Flash模型。很快发现一个头疼的问题&#xff1a;每次在办公室调试好的技能参数&#…...

Dify私有化部署实战:如何在企业内网快速搭建AI开发平台(含Docker镜像打包技巧)

Dify私有化部署实战&#xff1a;企业内网AI开发平台搭建全攻略 1. 企业内网部署Dify的核心价值与挑战 在数字化转型浪潮中&#xff0c;越来越多的企业开始将AI能力纳入核心业务系统。Dify作为开源的大语言模型应用开发平台&#xff0c;其私有化部署方案尤其适合对数据安全有严…...

保姆级教程:MogFace人脸检测模型-large快速上手,无需代码轻松体验

保姆级教程&#xff1a;MogFace人脸检测模型-large快速上手&#xff0c;无需代码轻松体验 1. 认识MogFace人脸检测模型 1.1 什么是MogFace MogFace是目前最先进的人脸检测方法之一&#xff0c;在Wider Face六项榜单上长期保持领先地位。这个模型通过三个创新点显著提升了检测…...

数据清洗避坑指南:缺失值和异常值处理的5个常见错误(附真实案例)

数据清洗避坑指南&#xff1a;缺失值和异常值处理的5个常见错误&#xff08;附真实案例&#xff09; 在电商平台的用户行为分析中&#xff0c;我们曾遇到一个诡异现象&#xff1a;某促销活动页面的转化率突然飙升到98%。进一步排查发现&#xff0c;是爬虫程序将未加载完成的页…...

背包问题Ⅱ与二分问题

今天我对背包问题有了更深的理解&#xff0c;我一定要写下来&#xff0c;巩固自己的思路并且&#xff0c;遇到新的难题二分&#xff0c;不管了&#xff0c;干就完了&#xff01;&#xff01;&#xff01;完全背包以今天写的代码展开详细描述与解释,并附上题目#define N 1001 in…...

Wan2.2-I2V-A14B镜像免配置实战:开箱即用,省去PyTorch/CUDA环境冲突烦恼

Wan2.2-I2V-A14B镜像免配置实战&#xff1a;开箱即用&#xff0c;省去PyTorch/CUDA环境冲突烦恼 1. 镜像概述与核心优势 Wan2.2-I2V-A14B是一款专为文生视频任务优化的私有部署镜像&#xff0c;基于RTX 4090D 24GB显存显卡和CUDA 12.4环境深度定制。这个镜像的最大特点是开箱…...

Dual-Tree Agent RAG:可控、可解释、可验证

从文本检索到方法推理的跃迁 传统RAG系统将文档切分为平面文本块&#xff0c;通过向量相似度检索来增强大模型生成。这种模式在简单事实问答中表现良好&#xff0c;却难以应对需要全局结构理解、跨章节整合和方法论复用的复杂创新任务。现有改进方案如RAPTOR&#xff08;层次摘…...

基于扩散模型的歌声合成技术:DiffSinger架构解析与实践应用

基于扩散模型的歌声合成技术&#xff1a;DiffSinger架构解析与实践应用 【免费下载链接】DiffSinger 项目地址: https://gitcode.com/gh_mirrors/dif/DiffSinger DiffSinger作为开源歌声合成领域的创新解决方案&#xff0c;通过扩散模型与深度学习技术的深度融合&#…...