@Transactional注解失效场景之——同类中方法调用,事务失效

2023-11-08



该篇博客为总结自己曾写下的Bug

一、亲身案例

当时的场景为:在controller层获取一笔交易单的信息(前台传给controller层为Map类型的键值对),然后controller层直接将这个Map参数对象转发给Service层,在Service层进行一个对象属性的封装,继而调用mapper层接口完成数据的持久化。


问题出现在Service层,由于这一笔交易单信息会涉及多张表的数据信息,为了代码结构的优美,我特地在Service层的方法中,调用同类中的另一个doSave()方法来完成数据持久化保存。最后再潇洒的为doSave()方法添加一个@Transactional注解,扬长而去。



悄悄的说,因为我自己在测试过程中就发现了问题,但是无奈自己不知道具体的原因。我便将最容易出错的那一个保存操作提到最前然,最不容易出错的放在了最后面。


将当时的代码抽象成下面的形式,此时的@Transactional注解,可以说是加了,但是又没有完全加上。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8MFgIyQQ-1628934558390)(@Transactional注解失效.assets/image-20210814173649318.png)]

@Component
public class MobianServiceImpl implements MobianService {

	@Override
	public int saveInfo(InfoVo infoVo) {
		User user = new User();
		Hobby hobby = new Hobby();

        // 组装对象过程。。。
		user.setId(infoVo.getUserId());
		user.setName(infoVo.getUserName());
		hobby.setHobby(infoVo.getHobbyName());
		hobby.setUserId(infoVo.getUserId());
        
        // 具体的保存操作。。。
		int i = doSave(user, hobby);
		return i;

	}

	@Transactional
	public int doSave(User user, Hobby hobby){
		int i = mobianMapper.saveUser(user);
        // 发生异常
		int err = 1/0;
		int i1 = mobianMapper.saveHobby(hobby);
		return i + i1;
	}
}





二、改进方式

1、根据@Transactional注解的原理出发(这个方式显得很呆)

@Component
public class MobianServiceImpl implements MobianService {

	@Autowired
	private MobianMapper mobianMapper;

	@Autowired
	private MobianServiceImpl mobianService;

	@Override
	public int saveInfo(InfoVo infoVo) {
		User user = new User();
		Hobby hobby = new Hobby();

        // 组装对象过程。。。
		user.setId(infoVo.getUserId());
		user.setName(infoVo.getUserName());
		hobby.setHobby(infoVo.getHobbyName());
		hobby.setUserId(infoVo.getUserId());
        
        // 具体的保存操作。。。
        // 获取Spring容器中的对象
		int i = mobianService.doSave(user, hobby);
		return i;
	}

	@Transactional
	public int doSave(User user, Hobby hobby){
		int i = mobianMapper.saveUser(user);
        // 发生异常
		int err = 1/0;
		int i1 = mobianMapper.saveHobby(hobby);
		return i + i1;
	}
}

2、将doSave方法写在其他的service类中,用一个service类调用另一个service类

3、直接在saveInfo方法上面添加@Transactional注解

4、int i = ((MobianServiceImpl ) AopContext.currentProxy()).doSave(user, hobby)

从底层出发,去AOP容器中获取对应的被动态处理后的doSave方法,不过还需要你补充对应的配置,配置如下:

  1. 通过注解添加配置(加在类上)
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
  1. 或通过xml配置文件添加配置
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

这样就解决了报错问题。```




三、原理分析

Spring中对于数据库事务的约定,其实现原理是AOP,而AOP又是通过动态代理去实现。(AOP是在Spring的生命周期中完成)。

以我们上面代码中为例,我们在方法内部调用doSave(),等同于this.doSave(),此处的this表示new MobianServiceImpl()对象,即调用这个类中的这个方法完成持久化。这是一个自调用的形式。



解决方法一,方式一之所以能够实现,是因为我们去Spring容器中获取到的mobianService容器对象不等于我们直接new出来的对象。有看过我之前文章的小伙伴就应该知道,他们为什么不是同一个:浅谈Spring中Bean的生命周期,Spring容器中获取的是new出来的对象的代理对象,前者包含后者。换句话说,Spring容器中的对象经过了AOP处理(处理@Transactional注解),所以具有事务的特点。但是我们直接new出来的对象,仅仅是一个对象,不具备事务的特点。


解决方法二,也是相同的原理来理解,因为我们由一个service调用另一个service时,另一个对象就是去Spring容器中获取的,这样就能以一种看似不起眼的方式转移解决方法一中看起来很瓜的方式。


解决方法三,直接在最顶层添加事务,这种方式很粗暴,可能会出现在某些复杂的业务场景中不适用的情况。




该Bug解决的场景为,写下Bug代码半年后的某天早晨,因为睡不着,起来看书突然就看到了这么一段对于这个注解的描述,瞬间茅塞顿开,后面去公司马上找到以前的代码,发现果然是这个问题。我真菜!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

@Transactional注解失效场景之——同类中方法调用,事务失效 的相关文章

  • 如何使用 FileChannel 将一个文件的内容附加到另一个文件的末尾?

    File a txt好像 ABC File d txt好像 DEF 我正在尝试将 DEF 附加到 ABC 所以a txt好像 ABC DEF 我尝试过的方法总是完全覆盖第一个条目 所以我总是最终得到 DEF 这是我尝试过的两种方法 File
  • 如何在一行中将字符串数组转换为双精度数组

    我有一个字符串数组 String guaranteedOutput Arrays copyOf values values length String class 所有字符串值都是数字 数据应转换为Double QuestionJava 中
  • 线程自动利用多个CPU核心?

    假设我的应用程序运行 2 个线程 例如渲染线程和游戏更新线程 如果它在具有多核 CPU 当今典型 的移动设备上运行 我是否可以期望线程在可能的情况下自动分配给不同的核心 我知道底层操作系统内核 Android linux内核 决定调度 我的
  • JNI 不满意链接错误

    我想创建一个简单的 JNI 层 我使用Visual studio 2008创建了一个dll Win 32控制台应用程序项目类型 带有DLL作为选项 当我调用本机方法时 出现此异常 Exception occurred during even
  • ExceptionConverter:java.io.IOException:文档没有页面。我正在使用 iText

    当我执行下面的代码时 File f new File c sample pdf PdfWriter getInstance document new FileOutputStream f document open System out p
  • Java8无符号算术

    据广泛报道 Java 8 具有对无符号整数的库支持 然而 似乎没有文章解释如何使用它以及有多少可能 有些函数 例如 Integer CompareUnsigned 很容易找到 并且似乎可以实现人们所期望的功能 但是 我什至无法编写一个简单的
  • IntelliJ IDEA 创建的 JAR 文件无法运行

    我在 IntelliJ 中编写了一个跨越几个类的程序 当我在 IDE 中测试它时它运行良好 但是 每当我按照教程将项目制作成 jar 可执行文件时 它就不会运行 双击 out 文件夹中的文件时 该文件不会运行 并显示 无法启动 Java J
  • CXF Swagger2功能添加安全定义

    我想使用 org apache cxf jaxrs swagger Swagger2Feature 将安全定义添加到我的其余服务中 但是我看不到任何相关方法或任何有关如何执行此操作的资源 下面是我想使用 swagger2feature 生成
  • jdbc4.MySQLSyntaxErrorException:数据库中不存在表

    我正在使用 SpringBoot 开发一个网络应用程序 这是我的application properties文件来指定访问数据库的凭据 spring datasource driverClassName com mysql jdbc Dri
  • hibernate总是自己删除表中的所有数据

    您好 我正在开发一个 spring mvc 应用程序 它使用 hibernate 连接到存储文件的 mysql 数据库 我有两个方法 一个方法添加我选择的特定文件路径中的所有文件 另一种方法调用查询以返回从 mysql 存储的文件列表 问题
  • Spring引导@Transactional

    spring boot会自动在controller层添加 Transactional注解吗 我尝试将 Transactional 放在服务层 但似乎控制器层覆盖了注释 我有这个配置
  • Clip 在 Java 中播放 WAV 文件时出现严重延迟

    我编写了一段代码来读取 WAV 文件 大小约为 80 mb 并播放该文件 问题是声音播放效果很差 极度滞后 你能告诉我有什么问题吗 这是我的代码 我称之为doPlayJframe 构造函数内的函数 private void doPlay f
  • 在具有相同属性名称的不同数据类型上使用 ModelMapper

    我有两节课说Animal AnimalDto我想用ModelMapper将 Entity 转换为 DTO 反之亦然 但是对于具有相似名称的一些属性 这些类应该具有不同的数据类型 我该如何实现这一目标 动物 java public class
  • Spring Data 与 Spring Data JPA 与 JdbcTemplate

    我有信心Spring Data and Spring Data JPA指的是相同的 但后来我在 youtube 上观看了一个关于他正在使用JdbcTemplate在那篇教程中 所以我在那里感到困惑 我想澄清一下两者之间有什么区别Spring
  • 尝试使用 Ruby Java Bridge (RJB) gem 时出现错误“无法创建 Java VM”

    我正在尝试实现 Ruby Java Bridge RJB gem 来与 JVM 通信 以便我可以运行 Open NLP gem 我在 Windows 8 上安装并运行了 Java 所有迹象 至少我所知道的 都表明 Java 已安装并可运行
  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • 使用 AWS Java SDK 为现有 S3 对象设置 Expires 标头

    我正在更新 Amazon S3 存储桶中的现有对象以设置一些元数据 我想设置 HTTPExpires每个对象的标头以更好地处理 HTTP 1 0 客户端 我们正在使用AWS Java SDK http aws amazon com sdkf
  • Android JNI C 简单追加函数

    我想制作一个简单的函数 返回两个字符串的值 基本上 java public native String getAppendedString String name c jstring Java com example hellojni He
  • Springs 元素“beans”不能具有字符 [children],因为该类型的内容类型是仅元素

    我在 stackoverflow 中搜索了一些页面来解决这个问题 确实遵循了一些正确的答案 但不起作用 我是春天的新人 对不起 这是我的调度程序 servlet
  • 查看Jasper报告执行的SQL

    运行 Jasper 报表 其中 SQL 嵌入到报表文件 jrxml 中 时 是否可以看到执行的 SQL 理想情况下 我还想查看替换每个 P 占位符的值 Cheers Don JasperReports 使用 Jakarta Commons

随机推荐

  • 线程-Linux下的轻量级进程

    首先我们知道 每个进程都是在各自独立的地址空间上运行 如果要同时完成好几个任务 比如你一边在下载软件 另一边在进行着其他的操作 那么试想一下 可不可以在一个进程里面把这几个事件同时进行呢 这里就要提到线程的概念了 但其实Linux中 并没有
  • Unity 实用代码 小工具

    Unity 实用代码 小工具 Unity 屏幕截图 全屏截图方法 全屏截图方法 带委托事件 自定义截图方法 自定义截图方法 带委托 延迟工具 携程延迟方法 携程延迟带委托方法 场景加载 场景加载 方法 场景加载方法 带委托 异步场景加载 方
  • Warning: This development build of composer is over 60 days old

    今天查看了一下服务器安装的Composer版本 报了一个警告 意思是安装已经超过60天了 需要执行 usr bin composer self update 升级到最新版本 然后我就执行了 再次查看版本确实更新到官方最新的1 7 3版本 但
  • PTA7(python3)

    python程序设计07 字符串与正则表达式 7 1 找最后的字符 30 分 7 2 重要的事情说N遍 20 分 7 3 号码牌的制作 10 分 7 4 统计字符串中指定字符的个数 30 分 7 5 字符串消除空格 30 分 7 6 统计指
  • 三分钟弄懂物联网流行协议——MQTT

    MQTT Message Queue Telemetry Transport 翻译成中文就是 遥测传输协议 其主要提供了订阅 发布两种消息模式 更为简约 轻量 易于使用 特别适合于受限环境 带宽低 网络延迟高 网络通信不稳定 的消息分发 属
  • C++中vector迭代器失效问题及其解决方法

    C 中vector迭代器失效问题及其解决方法 迭代器的主要作用就是让算法能够不用关心底层数据结构 其底层实际就是一个指针 或者是对指针进行了封装 比如 vector的迭代器就是原生态指针T 因此迭代器失效 实际就是迭代器底层对应指针所指向的
  • php socket error 111,php中的socket_connect上的“连接被拒绝”错误

    我试图将一些代码从perl转换为php Perl代码如下所示 my handle Connect port host 我试图使用socket在PHP中做同样的事情 我试过socket create和socket connect socket
  • Windows(10/11)端vscode开发、调试远程Linux(Ubuntu14.04)端c++ 开发环境部署步骤

    1 安装vscode 进入https code visualstudio com 即vsocde官网选择Windows x64版本下载并安装 安装过程中推荐勾选往右键菜单添加通过vscode打开文件夹的选项 2 vsocde插件安装 打开v
  • 《影响力》第七章:稀缺

    稀缺 物以稀为贵 稍纵即逝 越是得不到就越觉得香 这是为啥 至于是不是真的香 由于得不到 也不得而知 例如 我有一个朋友觉得佐佐木希如果能娶来做老婆是很香的 简直就是夫复何求 然而这世上当真有人会把女神娶回家然后出轨还家暴 这说来还真是让人
  • 判断点是否在任意多边形内(java)

    import java util ArrayList public class Test public static void main String args double px 113 0253 double py 23 98049 A
  • 文心一言和讯飞星火全面对比测试:(三)常识问题

    前文回顾 在 一 语言理解能力测试中 我们主要测试了两个大语言模型对复杂语义的理解 对文章情绪的识别 对文章进行摘要总结 对文章进行要素提取 测试结果表明 在语言理解能力上 除了有些问题他拒绝回答之外 讯飞星火的表现明显要好于文心一言 可以
  • 函数和windows对象 有惊喜✔

    一 函数 函数的定义 类似于Java中的方法 是完成特定任务的代码语句块 1 系统函数 eval lt 表达式 gt 得到一个文本框的值 表单 例 var sname eval doucment form sname value parse
  • Java多线程导致CPU占用100%解决及线程池正确关闭方式

    文章目录 前言 一 cpu占用高排查问题 二 解决办法 使用AtomicLong 统计线程是否完成 再执行executor submit 提交新的任务导队列中 三 多线程关闭与令牌限流 前言 情景 1000万表数据导入内存数据库 按分页大小
  • 超详细java web实验环境 (4) Eclipse配置Tomcat配置

    目录 一 确保Tomcat服务器处于关闭状态 二 在Eclipse中配置Tomcat 三 测试Tomcat是否配置完成 四 若出现异常 一 确保Tomcat服务器处于关闭状态 二 在Eclipse中配置Tomcat 1 打开Eclipse
  • C++类与对象:拷贝构造函数&浅拷贝

    标题 拷贝构造函数 默认拷贝构造 应用一 用已存在的类类型对象创建新对象 1 类中不涉及资源管理 可以使用默认拷贝构造函数 2 类中涉及资源管理 应用二 函数参数为类类型 应用三 函数返回值为类类型 拷贝构造函数 目的 为了初始化新对象 同
  • docker入门实践,实战搭建nginx续集,利用Dockerfile制作属于自己的镜像

    前言 在看这一篇之前 可以先回顾一下使用现成的nginx镜像在搭建 https blog csdn net hl java article details 86232900 可以发现 搭建成功后 服务是可以访问的 http localhos
  • Android Studio汉化教程

    先去AS的官网下载一个 AS官网 1 下载汉化包 AS汉化包下载地址 2 找到AS安装目录 然后找到lib文件夹 lib文件夹里面有一个resources en的东东 将该文件复制到桌面 并改名为resources cn 然后用解压工具打开
  • QT之获取布局内容及删除布局

    1 删除布局 图1 QLayout p ui gt verticalLayout 7 gt itemAt 0 gt layout while p gt count QWidget pWidget p gt itemAt 0 gt widge
  • 图像修复(Image Inpainting)任务中常用的掩码数据集

    文章目录 前言 mask数据集分类及介绍 总结 前言 在 Image Inpainting 图像修复 任务中 需要使用掩码数据集在图像上人为添加缺陷区域 以便在设计的深度学习上进行训练学习 mask数据集分类及介绍 目前图像修复任务中最长用
  • @Transactional注解失效场景之——同类中方法调用,事务失效

    文章目录 一 亲身案例 二 改进方式 三 原理分析 该篇博客为总结自己曾写下的Bug 一 亲身案例 当时的场景为 在controller层获取一笔交易单的信息 前台传给controller层为Map类型的键值对 然后controller层直