@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秒

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

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

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;交互…

学英语学压测: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;旨在为神经科学研究人员提供一个高效、精确的数据…

OKHttp调用第三方接口,响应转string报错okhttp3.internal.http.RealResponseBody@4a3d0218

原因分析 通过OkHttp请求网络&#xff0c;结果请求下来的数据一直无法解析并且报错&#xff0c;因解析时String res response.body().toString() 将toString改为string即可&#xff01;

oceanbase集群访问异常问题处理

1.报错现象 2.问题排查 检查obproxy状态发现为不可用状态 重启obproxy 依次重启Obproxy集群 观察任务状态 重启完成 Obproxy状态正常 3.验证登录 登录成功

ruckus R510升级到Unleashe后不能访问

ruckus R510 是IPQ4019&#xff0c;升级到Unleashe&#xff0c;它弹窗提示 但是这个IP没办法用&#xff0c;访问不了AP。 必应了一下&#xff0c;官方提示用advance ip scanner扫描。 扫描持续好久&#xff0c;发现IP竟然是从主路由获得。 9090的端口不用填&#xff0c;甚至不…

使用R语言绘制标准的中国地图和世界地图

在日常的学习和生活中&#xff0c;有时我们常常需要制作带有国界线的地图。这个时候绘制标准的国家地图就显得很重要。目前国家标准地图服务系统向全社会公布的标准中国地图数据&#xff0c;是最权威的地图数据。 今天介绍的R包“ggmapcn”&#xff0c;就是基于最新公布的地图…

linux上安装MySQL教程

1.准备好MySQL压缩包&#xff0c;并进行解压 tar -xvf mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar -C /usr/local 2.检查是否有mariadb数据库 rpm -aq|grep mariadb 关于mariadb:是MySQL的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可 MariaDB的目…

计算机网络基础(7)中科大郑铨老师笔记

应用层 目标&#xff1a;  网络应用的 原理&#xff1a;网络应用协议的概念和实现方面 传输层的服务模型 客户-服务器模式 对等模式(peerto-peer) 内容分发网络  网络应用的 实例&#xff1a;互联网流行的应用层协 议  HTTP  FTP  SMTP / POP3 / IMAP  DNS…

Spring源码分析之事件机制——观察者模式(二)

目录 获取监听器的入口方法 实际检索监听器的核心方法 监听器类型检查方法 监听器的注册过程 监听器的存储结构 过程总结 Spring源码分析之事件机制——观察者模式&#xff08;一&#xff09;-CSDN博客 Spring源码分析之事件机制——观察者模式&#xff08;二&#xff…

CSS——4. 行内样式和内部样式(即CSS引入方式)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>方法1&#xff1a;行内样式</title></head><body><!--css引入方式&#xff1a;--><!--css的引入的第一种方法叫&#xff1a;行内样式将css代码写…