请你谈谈:针对Mybatis引出的Spring事务的探究2:spring事务的失效

Spring事务失效的常见场景主要包括以下几个方面,这些场景通常是由于对Spring事务管理机制的误解或不当使用所导致的:

  1. 方法访问级别不当
    • 如前所述,Spring AOP默认不会拦截非public方法。因此,如果@Transactional注解被放置在一个非public方法(如private、protected或默认访问级别)上,那么该方法上的事务管理将不会生效。

在Spring AOP(面向切面编程)中,默认情况下,AOP代理不会拦截非public方法(包括private、protected以及默认访问级别的方法)。这是因为Spring AOP主要依赖于Java的动态代理机制,而Java的动态代理(无论是基于接口的JDK动态代理还是基于类的CGLIB代理)都有一些限制。

对于JDK动态代理,它要求被代理的对象必须实现至少一个接口,且代理方法仅限于接口中定义的方法。由于private、protected和默认访问级别的方法不是接口的一部分,因此它们不会被JDK动态代理拦截。

对于CGLIB代理,虽然它可以代理没有实现接口的类,但它也主要用于拦截public和protected方法(在某些情况下,CGLIB也可能拦截包级私有的方法,但这取决于具体的版本和配置)。然而,从Spring AOP的角度来看,通常不期望CGLIB去拦截private方法,因为这样做违反了封装的原则。

因此,当你尝试在一个非public方法上放置@Transactional注解时,由于该方法不会被Spring AOP代理拦截,所以事务管理将不会生效。

在这里插入图片描述
2. 类内部方法调用

  • 当一个标注了@Transactional的方法在类内部被另一个方法调用时,如果调用是通过this关键字进行的,那么调用将不会通过Spring的代理对象,因此事务管理将不会生效。这是因为Spring AOP是基于代理的,而类内部的方法调用会绕过代理。
  1. 异常处理不当
    • Spring默认只在遇到运行时异常(RuntimeException)和错误(Error)时回滚事务。如果方法抛出了检查型异常(checked exception),并且该异常没有被捕获或显式地标记为需要回滚(通过@Transactional的rollbackFor属性),则事务不会回滚。

异常处理不当导致Spring事务失效的情况,通常发生在事务方法内部捕获了异常,但没有正确地将异常抛出给Spring的事务管理器,从而导致Spring无法识别到需要回滚事务的异常。在Spring中,默认情况下,只有运行时异常(RuntimeException及其子类)和错误(Error及其子类)会导致事务回滚。如果方法捕获了这些异常并进行了处理(比如吞掉了异常),而没有重新抛出,那么Spring就不会知道发生了需要回滚事务的情况。
在这里插入图片描述

以下是一个具体的例子来说明异常处理不当导致事务失效的情况:

@Service
public class MyService {@Autowiredprivate MyRepository myRepository;@Transactionalpublic void processData() {try {// 假设这里进行了一些数据库操作myRepository.save(new MyEntity(/* ... */));// 这里故意制造一个运行时异常来模拟操作失败throw new RuntimeException("Database operation failed!");} catch (RuntimeException e) {// 这里捕获了异常,但没有重新抛出// 这将导致Spring不知道需要回滚事务System.err.println("Caught exception: " + e.getMessage());// ... 可能进行了一些日志记录或其他处理// 但没有 return; 或 throw e; 来传播异常}// 由于异常被吞掉了,这里的代码仍然会执行// 这可能不是你所期望的,特别是当它与数据库操作相关时// ...}
}

在这个例子中,processData方法被标注了@Transactional,意味着它应该在一个事务的上下文中执行。然而,当方法内部发生运行时异常时,这个异常被捕获了,但并没有被重新抛出。因此,Spring的事务管理器无法检测到这个异常,也就不会自动触发事务的回滚。结果,尽管发生了异常,但之前的数据库操作可能已经被提交到了数据库中,这通常不是我们想要的结果。

为了修复这个问题,你应该在捕获异常后重新抛出它,或者至少确保在捕获异常后不会执行任何可能依赖于事务成功的后续操作。以下是一个修复后的例子:

@Service
public class MyService {@Autowiredprivate MyRepository myRepository;@Transactionalpublic void processData() {try {// 假设这里进行了一些数据库操作myRepository.save(new MyEntity(/* ... */));// 这里故意制造一个运行时异常来模拟操作失败throw new RuntimeException("Database operation failed!");} catch (RuntimeException e) {// 捕获异常后,可以选择记录日志或进行其他处理System.err.println("Caught exception: " + e.getMessage());// ...// 然后重新抛出异常,以便Spring可以回滚事务throw e;}// 由于异常被重新抛出了,这里的代码不会执行// ...}
}

在这个修复后的例子中,当捕获到异常时,它被重新抛出了。这样,Spring的事务管理器就能够检测到这个异常,并触发事务的回滚。

确实,Spring 的事务管理默认只会在遇到运行时异常(RuntimeException)和错误(Error)时自动回滚事务。如果方法抛出了检查型异常(即非运行时异常,需要显式地声明抛出或捕获的异常),并且没有特别的配置来指示 Spring 需要对这些异常进行事务回滚,那么事务将不会回滚。

以下是一个例子,展示了当方法抛出检查型异常时,如何由于默认行为导致事务不会回滚:

@Service
public class MyService {@Autowiredprivate MyRepository myRepository;@Transactionalpublic void processData() throws MyCustomException {// 假设这里进行了一些数据库操作myRepository.save(new MyEntity(/* ... */));// 这里抛出了一个检查型异常throw new MyCustomException("Something went wrong!");}// 自定义的检查型异常public static class MyCustomException extends Exception {public MyCustomException(String message) {super(message);}}
}// 调用 MyService.processData 方法的客户端
public class Client {@Autowiredprivate MyService myService;public void execute() {try {myService.processData();} catch (MyService.MyCustomException e) {// 捕获了 MyCustomException,但没有重新抛出或标记为需要回滚System.err.println("Caught MyCustomException: " + e.getMessage());// 事务不会回滚,因为 MyCustomException 是检查型异常,并且没有被特别配置为需要回滚}}
}

在这个例子中,MyService.processData 方法抛出了一个自定义的检查型异常 MyCustomException。当这个方法被 Client 类的 execute 方法调用时,MyCustomException 被捕获了,但没有被重新抛出或进行任何特别的处理来指示 Spring 需要回滚事务。因此,尽管在事务方法中抛出了异常,但由于它是检查型异常,并且没有被 @TransactionalrollbackFor 属性特别指定为需要回滚的异常类型,所以事务不会回滚。

要解决这个问题,你有几个选项:

将检查型异常转换为运行时异常:在 processData 方法内部或调用它的地方,将检查型异常包装在运行时异常中抛出。

使用 @TransactionalrollbackFor 属性:在 processData 方法上的 @Transactional 注解中,使用 rollbackFor 属性来指定哪些检查型异常应该触发事务回滚。

@Transactional(rollbackFor = MyService.MyCustomException.class)
public void processData() throws MyCustomException {// ...
}
  1. 错误的传播行为

    • @Transactional注解的propagation属性定义了事务的传播行为。如果设置了不恰当的值(如PROPAGATION_NEVER,表示永远不在当前方法上开启新事务),则可能导致事务不生效。
  2. 未被Spring管理

    • 如果事务方法所在的类没有加载到Spring IOC容器中,也就是说,事务方法所在的类没有被Spring管理,则Spring事务会失效,示例如下
public class ProductService {@Autowiredprivate ProductDao productDao;@Transactionalpublic void updateProductStockCountById(Integer stockCount, Long id){productDao.updateProductStockCountById(stockCount, id);}
}
  1. 事务管理器配置错误

    • Spring事务管理依赖于正确配置的事务管理器。如果事务管理器的配置有误(如bean的ID不正确、属性设置错误等),则事务将不会按预期工作。
  2. 多线程事务管理

    • 在多线程环境中,每个线程都有自己独立的事务上下文。如果在一个线程中启动了一个事务,然后在另一个线程中执行数据库操作,那么这些操作将不会受到原始线程事务的控制。虽然这不一定意味着事务“失效”,但它确实会导致事务行为与预期不符。
  3. 代理模式问题

    • Spring的AOP实现依赖于代理模式。如果代理模式配置不当(如使用了JDK动态代理但类实现了多个接口,或者使用了CGLIB代理但类没有实现接口),则可能会导致AOP拦截器(包括事务拦截器)无法正确工作。
  4. 数据库或表不支持事务

    • Spring事务生效的前提是所连接的数据库要支持事务,如果底层的数据库都不支持事务,则Spring的事务肯定会失效。例如,如果使用的数据库为MySQL,并且选用了MyISAM存储引擎,则Spring的事务就会失效。

为了避免这些常见的Spring事务失效场景,开发者需要深入理解Spring事务管理的原理和限制,并仔细检查和测试他们的代码和配置。

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

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

相关文章

通信原理-实验六:实验测验

实验六 实验测验 一:测验内容和要求 测试需要完成以下几个步骤: 配置好以下网络图;占总分10%(缺少一个扣一分)根据下面图配置好对应的IP和网关以及路由等相关配置,保证设备之间连通正常;占总…

《AIGC 实战宝典》(2024版) 正式发布!

2024 新年伊始,OpenAI 推出文生视频 Sora,风靡整个科技圈。 最近又发布了 ChatGPT-4o,这是一个全新模型,不仅能处理文本,还能实时理解和生成音频和图像。OpenAI 用实际行动给全世界的科技公司又上了一课。 如何从0到1…

C++(week14): C++提高:(一)面向对象设计:设计原则、设计模式

文章目录 一、面向对象设计的概念4.统一建模语言:UML语言StartUML 二、类与类之间的关系0.总结1.继承 (泛化耦合)2.组合 (Composition)3.聚合 (Aggregation)4.关联(1)双向关联(2)单向关联 5.依赖 (Dependency) 三、面向对象设计的原则0.总结1.单一职责原则 (Single …

你还以为前端无法操作文件吗

🧑‍💻 写在开头 点赞 收藏 学会🤣🤣🤣 这里面有个值得说明一点的问题是,我一直以为(可能有人跟我一样)前端是无法操作文件的,可实际上自从HTML5标准出现之后&#xff…

昇思25天学习打卡营第21天|CV-Shufflenet图像分类

打卡 目录 打卡 ShuffleNet 网络介绍 ShuffleNet 模型架构 Pointwise Group Convolution Channel Shuffle ShuffleNet模块 ShuffleNet 模块代码 构建ShuffleNet网络 模块代码 模型训练和评估 模型训练 模型评估 模型预测 ShuffleNet 网络介绍 ShuffleNetV1是旷视科…

数字图像处理笔记(三) ---- 傅里叶变换的基本原理

系列文章目录 数字图像处理笔记(一)---- 图像数字化与显示 数字图像处理笔记(二)---- 像素加图像统计特征 数字图像处理笔记(三) ---- 傅里叶变换的基本原理 文章目录 系列文章目录前言一、傅里叶变换二、离散傅里叶变…

JCR一区级 | Matlab实现TTAO-Transformer-LSTM多变量回归预测

JCR一区级 | Matlab实现TTAO-Transformer-LSTM多变量回归预测 目录 JCR一区级 | Matlab实现TTAO-Transformer-LSTM多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【JCR一区级】Matlab实现TTAO-Transformer-LSTM多变量回归预测,三角拓扑聚合…

【运维自动化-配置平台】模型及模型关联最小化实践

蓝鲸智云配置平台,以下简称配置平台 我们知道主机是配置平台最常见的管控资源对象,在业务拓扑里可以通过划分模块来清晰的可视化管理;那其他资源如何通过配置平台来纳管呢,比如网络设备交换机。场景需求:如何把交换机…

【Linux 驱动】IMX6ULL eLCDIF参考手册翻译

1. eLCDIF 1.1 概述 eLCDIF是一种通用的显示控制器,用于驱动各种尺寸和性能不同的显示设备。 eLCDIF块支持以下功能: 支持MPU接口(8080模式和6800模式)支持DOTCLK接口(RGB接口)VSYNC模式:针对高…

Maven高级——详解

目录 一、分模块设计 二、分模块设计小实践 三、Maven继承 1.继承关系实现 ​编辑 2.版本锁定 dependencyManagement 自定义属性/引用属性 四、Maven聚合 五、Maven私服 一、分模块设计 为什么要分模块设计,将项目按照功能拆分分成若干个子模…

QT串口和数据库通信

创建串口 串口连接客户端并向服务器发送消息 client.pro #------------------------------------------------- # # Project created by QtCreator 2024-07-02T14:11:20 # #-------------------------------------------------QT core gui network QT core gui…

房屋出租系统 学习笔记 韩顺平 零基础30天学会Java(2024.7.15)

代码见package houserent P362 房屋出租需求 P363 房屋出租设计 分层模式 P364 房屋出租工具 给了一个工具包:Utility,使用:String s2 Utility.readString(10,”hspedu”);来限制输入字符大小最大是10,同时初始化的值为hspedu&a…

完全移动huggingface模型仓库(不是简单mv)

Linux中移动huggingface模型仓库 参考链接 先在bashrc中配置: export HF_DATASETS_CACHE"/your/path/dataset" export HF_HOME"/your/path/" export HUGGINGFACE_HUB_CACHE"/your/path/hub" export TRANSFORMERS_CACHE"/your…

速腾聚创激光雷达复现FAST-LIO

目录 1.软件环境 2.测试执行 3.代码学习 3.1.找主节点代码文件 3.2.整体流程结构 3.3.具体函数理解 记录复现FAST-LIO算法的过程和,代码梳理和理解 1.软件环境 Windows 10(64bits) VMware 16 Pro Ubuntu 20.04 ROS Noetic FAST-LIO的简化版、注释版。感谢…

Hospital 14.6.0全开源医院管理预约系统源码

InfyHMS 具有 60 种功能和 9 种不同类型的用户类型, 他们可以登录系统并根据他们的角色访问他们的数据。 源码下载:https://download.csdn.net/download/m0_66047725/89580674 更多资源下载:关注我。

Top-down Microarchitecture Analysis Method

1、英文链接: 1. https://www.intel.com/content/www/us/en/docs/vtune-profiler/cookbook/2023-0/top-down-microarchitecture-analysis-method.html 2. http://portal.nacad.ufrj.br/online/intel/vtune2017/help/GUID-02271361-CCD4-410C-8338-4B8158157EB6.ht…

LC61----1374. 生成每种字符都是奇数个的字符串(字符串)---java版

1.题目 2.思路 (1)题目要生成每种字符是奇数个的字符串。 (2)所以直接用参数n%2来判断。 (3)返回的字符串必须只含小写英文字母。如果存在多个满足题目要求的字符串,则返回其中任意一个即可。 (4)感觉题目不是很规范哈…

go程序在windows服务中优雅开启和关闭

本篇主要是讲述一个go程序,如何在windows服务中优雅开启和关闭,废话不多说,开搞!!!   使用方式:go程序 net服务启动 Ⅰ 开篇不利 Windows go进程编译后,为一个.exe文件,直接执行即…

知名医药医疗行业人工智能数字化转型讲师培训师唐兴通谈医药医疗销售与创新思维创新管理数字化AI及大客户销售医美生活美容品牌市场

​唐兴通 数字化商业创新顾问、数字化转型教练、沃顿商学院演讲嘉宾。全球商业思想大家EM罗杰斯(创新的扩散)、杰弗里摩尔(跨越鸿沟)、马修狄克逊(挑战式销售)、布兰登博格(竞合战略&#xff0…

css渐变色背景|<gradient

使用渐变色作为背景 可以直接将渐变色用作元素的背景&#xff0c;可以看做是一种特殊的背景图片。&#xff08;是作为背景background一个属性值不是背景颜色background-color的属性值 &#xff09; CSS 渐变是一种从一种颜色平滑过渡到另一种颜色的效果&#xff0c;由 <gra…