@Transcational注解为什么没有生效?

最近开发时遇到了需要使用事务的场景,之前的开发场景,都没有使用过事务,因此记录一下使用实践,以及踩坑。回想之前的开发经历,发现有一些场景是需要使用事务的,只不过当时开发经验有限,没想到使用事务😓😓

背景

需求背景很简单,就是有一些对数据库的操作,要求要不都执行成功,要不回滚,不允许出现一半成功、一半失败的情况,因此考虑使用事务实现。在Spring中,我们既可以使用@Transcational注解实现事务,也可以通过代码手动实现事务。

编程式事务

编程式事务,即通过代码实现,需手动设置事务状态,示例代码如下:

@Service
public class UserService {@Autowiredprivate TransactionTemplate transactionTemplate;@Autowiredprivate UserRepository userRepository;public void transferMoney(Long fromId, Long toId, BigDecimal amount) {// 使用TransactionTemplate进行事务管理transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus status) {try {User fromUser = userRepository.findById(fromId).orElseThrow(() -> new RuntimeException("用户不存在"));User toUser = userRepository.findById(toId).orElseThrow(() -> new RuntimeException("用户不存在"));fromUser.setBalance(fromUser.getBalance().subtract(amount));toUser.setBalance(toUser.getBalance().add(amount));userRepository.save(fromUser);userRepository.save(toUser);} catch (Exception e) {// 手动回滚事务status.setRollbackOnly();throw e;}}});}
}

声明式事务

声明式事务,即通过注解实现,其原理是通过AOP切面实现的。使用注解,可以将具体业务与事务处理部分解耦,代码侵入性很低,所以我们在开发过程中,使用注解的场景更多一些。但是使用注解也会有一些限制,我们会在后面说明。声明式事务示例代码如下:

@Service
public class UserService {@Autowiredprivate UserRepository userRepository;// 使用@Transactional注解声明事务@Transactional(rollbackFor = Exception.class)public void transferMoney(Long fromId, Long toId, BigDecimal amount) {User fromUser = userRepository.findById(fromId).orElseThrow(() -> new RuntimeException("用户不存在"));User toUser = userRepository.findById(toId).orElseThrow(() -> new RuntimeException("用户不存在"));fromUser.setBalance(fromUser.getBalance().subtract(amount));toUser.setBalance(toUser.getBalance().add(amount));userRepository.save(fromUser);userRepository.save(toUser);}
}

问题描述

/**
* 子模块处理真实逻辑
*/
public abstract void handleProcess(UserContext context);@Override
public boolean process(UserContext context) {// 前置逻辑处理try {handleProcess(context);} catch(Throwable t) {log.error("子模块处理异常:{}", ExceptionUtils.logStackTrace(t));return false;}return true;
}

问题代码如上所示,上述代码所在类是一个抽象类,里面有一个抽象方法。我们有一个子类继承了该抽象类,并实现了抽象方法。其相关代码如下所示:

public class ChildrenProcessPlugin extends BaseProcessPlugin {@ResourceUserService userService@Override@Transactional(rollbackFor = Exception.class)public void handleProcess(UserContext context) {// 前置处理userService.processUser();// 更新库表操作updateUserData();}
}

我在子类实现的handleProcess方法上添加了@Transactional注解,希望该方法的执行可以实现事务性,即handleProcess方法中抛出异常时,整个方法对数据库的操作可以自动回滚。(注意,userService.processUser()方法也被@Transactional注解修饰)。

但是在实际测试时,发现测试结果并不符合预期:当updateUserData方法抛出异常时,userService.processUser()方法中对数据库的操作并没有回滚。

问题原因

首先请求了Claude大模型,它并没有分析出我写的代码存在问题,我让他修复代码,它给出了编程式事务的方式,用这种方法,确实可以解决问题,但是这不是我想要的,因此继续去网上查询资料。在https://juejin.cn/post/6844904096747503629中发现了问题所在,这篇文章介绍了6种注解失效的场景,我们的场景符合第4类:**同一个类中方法调用,导致@Transactional注解失效。**详细介绍就是比如有一个类Test,它的一个方法A,A再调用本类的方法B(无论方法B是用public还是private修饰),但方法A没有被事务注解修饰,而B方法被事务注解修饰。则在外部方法调用方法A之后,方法B的注解是不会生效的。那么为什么不起作用呢?其实还是由于注解的事务是使用Spring AOP注解实现的,因为只有当事务方法被当前类以外的方法调用时,才会由Spring生成的代理对象来管理。Spring创建的代理对象只能拦截从外部进入类的方法调用。当在类的内部进行方法调用时,这些调用不会经过代理类,因此不会触发事务管理逻辑。

问题解决

将**@Transactional注解**加在最外层被调用的方法上,且注意最外层被调用的方法不得catch住所有异常而不抛出。如果无法在最外层被调用的地方添加注解(比如该方法是个抽象方法,其他实现方法不需要事务性),则可以通过编程式事务显式处理。

后话

除了此种场景外,其他**@Transactional**失效的场景我们也需要注意下:

  1. @Transactional注解需要应用在public方法上,非public方法不生效;
  2. @Transactional注解属性propagation设置错误,没有开启事务;
  3. @Transactional注解属性rollbackFor设置错误(默认针对非检查异常或者Error才回滚事务)
  4. 异常被你的catch”吃了”导致**@Transactional**失效
  5. 数据库引擎本身不支持事务(如果数据库引擎本身不支持事务,如MyISAM,则事务不会生效)

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

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

相关文章

传感器与检测技术基础知识

传感器检测系统 检测系统的组成:传感器、信号调理、数握采集、信号处理、信号显示、信号输出、输入设备、稳压电源。 检测系统的基本误差分类:绝对误差、相对误差、引用误差,最大引用误差。 测量系统的误差分类:系统误差、随机误差、粗大误…

决定系数(R²分数)——评估回归模型性能的一个指标

目录 1.定义 2.计算举例 3. 结果分析 1.定义 R(R平方)分数,也称为决定系数,是用来评估回归模型性能的一个指标。它表示自变量解释因变量变异性的比例。R分数的取值范围通常在0到1之间,其值越接近1,说明…

stm32HAL库使LED闪烁

PC13引脚为开漏接法 生成代码时设置为out put open drain gpio out put level 设置为high 1表示熄灭 我们将pa9引脚连接为推挽接法 生成代码时设置为 out put push pull Gpio out put level 设置为low 0 表示熄灭 代码使其亮起再延时0.5秒再熄灭再延时0.5秒

对一个双向链表,从尾部遍历找到第一个值为x的点,将node p插入这个点之前,如果找不到,则插在末尾。使用C语言实现

以下是一个用C语言实现的双向链表&#xff08;Doubly Linked List&#xff09;插入操作的代码。该代码从尾部遍历找到第一个值为x的节点&#xff0c;并在其前插入新节点p&#xff0c;或者在未找到时将其插入链表末尾。 #include <stdio.h> #include <stdlib.h>// 定…

Linux(Centos 7.6)基础命令/常用命令说明

1.目录相关命令 命令命令说明pwd用于显示/打印当前目录位置。ls/ll 列出当前目录下的文件或者目录&#xff0c;ll是ls -l的别名&#xff0c;ls仅显示名称&#xff0c;ll会显示详细的目录文件信息。 cd目录切换&#xff0c;常见用法有&#xff0c;cd /切换到根目录&#xff0c;…

矩阵运算提速——玩转opencv::Mat

介绍:用Eigen或opencv::Mat进行矩阵的运算&#xff0c;比用cpp的vector或vector进行矩阵运算要快吗? 使用 Eigen 或 OpenCV 的 cv::Mat 进行矩阵运算通常比使用 std::vector<int> 或 std::vector<double> 更快。这主要有以下几个原因&#xff1a; 优化的底层实现…

python文件操作相关(excel)

python文件操作相关&#xff08;excel&#xff09; 1. openpyxl 库openpyxl其他用法创建与删除操作单元格追加数据格式化单元格合并单元格插入图片公式打印设置保护工作表其他功能 2. pandas 库3. xlrd 和 xlwt 库4. xlsxwriter 库5. pyxlsb 库应用场景参考资料 在 Python 中&a…

C++ 基础概念: 未定义行为(Undefined Behavior)

文章目录 Intro如何正确认识 UB有多少未定义行为?对 UB 的误解 C 标准定义的几种行为1. 定义的行为 (defined behavior)2. 实现定义的行为 (implementation defined behavior)3. 未指定的行为 (unspecified behavior)4. 未定义行为 (undefined behavior)揭晓答案 C 中如何定义…

yolo小damo合集

效果如下&#xff1a;这个是图片检测 效果如下&#xff1a;这个是视频检测 效果如下&#xff1a;这个是摄像头检测 1 相关库 除了yolov11所用库之外&#xff0c;本文所用到的额外库为pyqt5&#xff0c;输入指令进行安装 pip install pyqt5 导入所需要的库 import sys fro…

【蓝桥杯研究生组】第14届Java试题答案整理

试题链接&#xff1a;链接 A题 满足条件的答案有&#xff1a;35813116 public class TianShu {public static void main(String[] args) {int ans 0;// 2000.1.1 - 2000000.1.1// 年份是月份的倍数&#xff0c;也是日的倍数for (int year2000; year<2000000; year) {for …

基于Java的超级玛丽游戏的设计与实现【源码+文档+部署讲解】

目 录 1、绪论 1.1背景以及现状 1.2 Java语言的特点 1.3 系统运行环境及开发软件&#xff1a; 1.4 可行性的分析 1.4.1 技术可行性 1.4.2 经济可行性 1.4.3 操作可行性 2、 需求分析 2.1 用户需求分析 2.2功能需求分析 2.3界面设计需求分析…

25考研王道数据机构课后习题-----顺序表链表部分

文章目录 1.顺序表题目2.链表相关题目3.我的个人总结 声明&#xff1a;以下内容来自于B站知名up主白话拆解数据结构&#xff0c;望获悉&#xff1b; 1.顺序表题目 下面的这个说的是&#xff1a;下面的哪一个是组成我们的顺序表的有限序列&#xff0c;这个应该是数据元素&#x…

LLM - 使用 LLaMA-Factory 部署大模型 HTTP 多模态服务 (4)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144881432 大模型的 HTTP 服务&#xff0c;通过网络接口&#xff0c;提供 AI 模型功能的服务&#xff0c;允许通过发送 HTTP 请求&#xff0c;交互…

Spring Boot 各种事务操作实战(自动回滚、手动回滚、部分回滚)

概念 事务定义 事务&#xff0c;就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行&#xff0c;我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行&#xff0c;我们称该事务被提交。…

学英语学压测:02jmeter组件-测试计划和线程组ramp-up参数的作用

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#xff1a;先看关键单词&#xff0c;再看英文&#xff0c;最后看中文总结&#xff0c;再回头看一遍英文原文&#xff0c;效果更佳&#xff01;&#xff01; 关键词 Functional Testing功能测试[ˈfʌŋkʃənəl ˈtɛstɪŋ]Sample样…

多线程访问FFmpegFrameGrabber.start方法阻塞问题

一、背景 项目集成网络摄像头实现直播功能需要用到ffmpeg处理rtmp视频流进行web端播放 通过网上资源找到大神的springboot项目实现了rtmp视频流转为http请求进行视频中转功能&#xff0c;其底层利用javacv的FFmpegFrameGrabber进行拉流、推流&#xff0c;进而实现了视频中转。 …

医学图像分析工具01:FreeSurfer || Recon -all 全流程MRI皮质表面重建

FreeSurfer是什么 FreeSurfer 是一个功能强大的神经影像学分析软件包&#xff0c;广泛用于处理和可视化大脑的横断面和纵向研究数据。该软件由马萨诸塞州总医院的Martinos生物医学成像中心的计算神经影像实验室开发&#xff0c;旨在为神经科学研究人员提供一个高效、精确的数据…

在Microsoft Windows上安装MySQL

MySQL仅适用于Microsoft Windows 64位操作系统&#xff0c;在Microsoft Windows上安装MySQL有不同的方法&#xff1a;MSI、包含您解压缩的所有必要文件的标准二进制版本&#xff08;打包为压缩文件&#xff09;以及自己编译MySQL源文件。 注意&#xff1a;MySQL8.4服务器需要在…

探索最新的编程技术趋势:AI 编程助手和未来的编程方式

随着技术的飞速发展&#xff0c;编程技术领域在近年来经历了深刻的变革。从人工智能到低代码开发工具&#xff0c;新的技术趋势不断涌现&#xff0c;不仅大幅提高了开发效率&#xff0c;也重新定义了开发者的角色和工作方式。本篇博客将探讨几项当前最值得关注的编程技术&#…

k8s集群,CRI-Docker部署条件及方法

CRI-Docker部署条件及方法 文章目录 CRI-Docker部署条件及方法CRI-Docker使用条件安装 cri-docker 的步骤&#xff1a; CRI-Docker使用条件 在 Kubernetes 1.20 及以上版本&#xff0c;kubeadm 默认使用 containerd 作为容器运行时&#xff08;Container Runtime Interface, C…