Spring事务管理失效的原因

8个Spring事务失效的场景,你碰到过几种? 作为Java开发工程师,相信大家对Spring种事务的使用并不陌生。但是你可能只是停留在基础的使用层面上,在遇到一些比较特殊的场景,事务可能没有生效,直接在生产上暴露了,这可能就会导致比较严重的生产事故。今天,我们就简单来说下Spring事务的原理,然后总结一下spring事务失败的场景,并提出对应的解决方案。本文简单阐述了下Spring中事务实现的原理,同时列举了8种Spring事务失败的场景,相信很多朋友可能都遇到过, 失败的原因也有详细说明。希望大家对Spring事务有一个新的认识。 阅读详情

个人认为, spring的声明式事务是spring让人感觉用的最爽的功能之一. 可是在有些时候, 我们使用spring的声明式事务时却并没有效果. 是spring的问题吗? 下面我们先大致说明一下spring声明式事务的原理, 然后再分析在什么情况下, spring的声明式事务会失效.

代理模式

我们知道, spring的声明式事务是基于代理模式的. 那么说事务之前我们还是大致的介绍一下代理模式吧. 其实代理模式相当简单, 就是将另一个类包裹在我们的类外面, 在调用我们创建的方法之前, 先经过外面的方法, 进行一些处理, 返回之前, 再进行一些操作. 比如:

public class UserService{
    ...
    public User getUserByName(String name) {
       return userDao.getUserByName(name);
    }
    ...
}

那么如果配置了事务, 就相当于又创建了一个类:

public class UserServiceProxy extends UserService{
    private UserService userService;
    ...
    public User getUserByName(String name){
        User user = null;
        try{
            // 在这里开启事务
            user = userService.getUserByName(name);
            // 在这里提交事务
        }
        catch(Exception e){
            // 在这里回滚事务

            // 这块应该需要向外抛异常, 否则我们就无法获取异常信息了. 
            // 至于方法声明没有添加异常声明, 是因为覆写方法, 异常必须和父类声明的异常"兼容". 
            // 这块应该是利用的java虚拟机并不区分普通异常和运行时异常的特点.
            throw e;
        }
        return user;
    }
    ...
}

然后我们使用的是 UserServiceProxy 类, 所以就可以"免费"得到事务的支持:

@Autowired
private UserService userService;    // 这里spring注入的实际上是UserServiceProxy的对象

private void test(){
    // 由于userService是UserServiceProxy的对象, 所以拥有了事务管理的能力
    userService.getUserByName("aa");
}

哪些情况下spring的事务管理会失效

private 方法, final 方法 和 static 方法不能添加事务

上面的东西并不难. 那么我们可以从上面知道些什么呢? 首先, 由于java继承时, 不能重写 private , final , static 修饰的方法. 所以, 所有的 private 方法, final 方法 和 static 方法 都无法 直接 添加spring的事务管理功能. 比如下面的代码(完整代码点击这里下载):

/**
 * 保存两个user对象. 添加了spring事务注解
 */
@Transactional
public final void saveErrorFinal(User user1, User user2) {
    UserDao userDao = getUserDao(); // 此处需要使用getUserDao方法. 不能直接使用userDao
    userDao.save(user1);
    System.out.println(10 / 0); // 引发异常
    userDao.save(user2);
}

/**
 * 静态方法. 添加了spring事务注解
 */
@Transactional
public static void saveErrorStatic(UserDao userDao, User user1, User user2) {
    userDao.save(user1);
    System.out.println(10 / 0); // 引发异常
    userDao.save(user2);
}

/**
 * 私有方法保存方法. 添加了spring事务注解
 */
@Transactional
private void saveErrorPrivate(User user1, User user2) {
    userDao.save(user1);
    System.out.println(10 / 0); // 引发异常
    userDao.save(user2);
}

测试代码如下:

/**
 * 检验user1是否插入成功, 并尝试删除数据. 如果没有插入, 则报错, 并退出.
 */
private void validateInsertSuccess() {
    User user = userService.getUserByName(user1.getName());
    userService.deleteByName(user1.getName()); // 删除用户数据
    assertNotEquals("插入失败!", -1, user.getId().intValue());
}

/**
 * 检验user1是否插入失败. 如果插入成功, 则删除数据, 并报错.
 */
private void validateInsertFail() {
    User user = userService.getUserByName(user1.getName());
    userService.deleteByName(user1.getName()); // 删除用户数据
    assertEquals("插入成功, 事务没有生效!" + user, -1, user.getId().intValue());
}

@Test
public void testSaveErrorFinal() {
    try {
        userService.saveErrorFinal(user1, user2);
    }
    catch (ArithmeticException e) {}    // 除零异常, 直接忽略
    validateInsertFail(); // 我们假设有事务支持, user1添加失败
}

@Test
public void testSaveErrorStatic() {
    try {
        UserService.saveErrorStatic(userDao, user1, user2);
    }
    catch (ArithmeticException e) {}
    validateInsertFail(); // 我们假设有事务支持, user1添加失败
}

由于 saveErrorPrivate 方法外面是无法调用的, 就暂时不去讨论了. 我们直接看 testSaveErrorFinal 和 testSaveErrorStatic 方法的运行结果:

很明显, 事务并没有生效. 也就是说 private 方法, final 方法 和 static 方法都没有事务支持.

没有通过代理对象调用添加事务的方法

仔细看看代理模式中的代码, 就会发现不通过代理对象调用方法也会导致spring事务管理失效. 绕过代理对象最直接的方法就是自己 new 一个对象, 虽然这种可能性非常小:

new UserService().save(user);

当然, 前面也说了, 这种可能性非常小. 那么我们看看第二种情况, 这种情况的可能性也不大:

/**
 * 保存两个user对象, 中间产生异常. 验证spring的事务是否可以正常工作
 */
@Transactional
public void saveError(User user1, User user2) {
    userDao.save(user1);
    System.out.println(10 / 0); // 引发异常
    userDao.save(user2);
}

/**
 * 通过{@link #saveError(User, User)}保存数据, 该方法本身并没有添加事务注解. 
 * 而是通过{@link #saveError(User, User)}方法使用事务
 */
public void saveByCallMethod(User user1, User user2) {
    //saveErrorPrivate(user1, user2);  // 或者调用saveErrorPrivate方法
    saveError(user1, user2);
}

由于测试的代码基本上和上面一样, 所以这里我们就不贴测试的代码了. 再说一次, 点击这里下载完整代码). 实际上, 上面的 saveByCallMethod 方法还是无法获得spring的事务支持. 因为它的调用堆栈如下图所示(从下向上):最终结果就是spring的事务管理没有生效. 这是或许你会想了, 那为啥不直接给 saveByCallMethod 方法添加事务支持呢? 对啊, 所以我说这种情况的可能性也不大. 下面我们再看看事务管理和多线程缠在一起时的情况:

/**
 * 通过创建一个新的线程, 调用{@link #saveError(User, User)}方法来保存用户, 该方法和
 * {@link #saveError(User, User)}方法都添加了事务注解
 */
@Transactional
public void saveByThread(User user1, User user2) {
    new Thread(() -> {
        try {
            Thread.sleep(1000); //耗时操作
            saveError(user1, user2);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("保存完成");
    }).start();
}

测试代码请参见我提供的完整代码. 这样的代码已经有可能了吧? 那么事务管理会生效吗? 我们再看看调用堆栈就知道了.结果和我们想的一样, spring的事务管理并没有生效.

总结

好了, 现在我们来回顾一下, 在那些情况下spring的事务管理会失效:

  • private 方法无法添加事务管理.
  • final 方法无法添加事务管理.
  • static 方法无法添加事务管理.
  • 当绕过代理对象, 直接调用添加事务管理的方法时, 事务管理将无法生效.
spring事务失效的11种场景 1 访问权限问题: java的访问权限有4种:private、default、protected、public,它们的权限从左到右,以此变大。如果在开发中,将事务方法定义了错误的访问权限,则事务功能会失效。 @Service public class EmpService { @Transactional private void add(UserModel userModel){ saveData(userModel); } } 如上:add方法的权限被定 阅读详情

相关推荐

java——@Transactional 在哪些情况下会失效?

Transactional注解在Spring框架中用于声明式事务管理,确保数据的一致性和可靠性。然而,在某些情况下,@Transactional注解可能会失效。通过遵循这些原则,可以最大程度地确保@Transactional注解在Spring框架中的正确性和有效性。

oopxiajun博客专栏 1455

Spring事务失效十种原因

本文详细的介绍了Spring事务失效的十种原因,掌握住它们并在工作避免这些情况。

m0_64830897的博客 7110

手把手拆解UCIe协议层:从Raw Mode到Flit Mode,数据包到底经历了什么?

本文深入解析UCIe协议层的数据包处理机制,从Raw Mode到Flit Mode的三大变体(Standard 256B、68B-Enhanced、Latency-Optimized),详细揭示数据包在不同模式下的封装与转换过程。通过工程师视角,展示协议层如何实现多模式动态切换、错误恢复及与D2D Adapter的协同设计,为芯片级互连技术提供实践指导。

weixin_28728495的博客 239

Spring 事务(Transactional)失效的七种原因及解决方案(含项目代码)

Spring框架提供了强大的事务管理功能,能够确保数据库操作的一致性和可靠性。然而,有时候我们可能会遇到Spring事务失效的情况,导致数据不一致或操作失败。本文将探讨Spring事务失效的原因,以及如何避免和解决这些问题。通过深入了解失效原因,我们可以更好地利用Spring事务管理功能,确保系统的稳定性和可靠性。

qq_45607784的博客 7755

STM32F103C8T6+I2C+DMA读取陀螺仪模块JY901S(硬件I2C

说明:1.本实验代码适用移植一切stm32f1系列;2.本实验使用的是外设资源硬件I2C2;3.本实验运用的是DMA单次模式,如果需要DMA的循环模式,请移步我的另一篇文章;4.本文章不提供陀螺仪校准教学,并是在没有校准陀螺仪情况下读取数据;5.本文章是作者的学习记录及心得,如有不足,欢迎指正。 总结:亲测stm32f103c8t6最小系统板通过片上外设资源I2C配合DMA读去陀螺仪模块jy901s偏航角有效。

anquanyuanqqadsy的博客 6172

测试dali协议的软件,DALI2.0和DALI1.0完美兼容同一个模块,测试每项可过协议

DALI2.0和DALI1.0完美兼容同一个模块,测试每项可过协议深圳聚积智能 夏先生 13246760327 QQ 349098308■IEC62386-102(V2.0)通过测试内容IEC62386-102/2.1/Test preambleIEC62386-102/3.1/Polarity testIEC62386-102/3.2/Maximum and minimum system v...

weixin_35343788的博客 1351

Spring事务失效原因及解决方法

spring 提供事务功能需要依赖于数据库的事务支持。而数据库层的事务提交和回滚是通过bin log 或者 redo log 实现的。大部分情况下我们使用基于 @Transactional 注解的声明式事务。声明式事务本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。对于Spring事务来说,在以下9种情况下会出现事务失效的情况。

m0_68642284的博客 2300

别再乱改宏定义了!STM32F103程序移植保姆级教程(从C8T6到ZET6实战)

本文详细解析了STM32F103程序从C8T6移植到ZET6的实战步骤,重点介绍了硬件差异、开发环境配置、时钟陷阱及外设处理等关键点。通过修改宏定义(如STM32F10X_HD)、调整启动文件和时钟配置,确保移植顺利进行。适合嵌入式开发者参考,避免常见移植问题。

weixin_42567497的博客 215

Spring 事务管理失效的十大原因

Spring 提供了强大的事务管理机制,极大地方便了开发者处理复杂的事务操作。然而,事务管理的有效性依赖于正确的配置和使用。在本文中,我们深入探讨了 Spring 事务管理失效的十大常见原因,并提供了详细的解决方案和代码示例。

qq_42798343的博客 1343

HMC5883L磁力计驱动开发:I²C通信、校准与FreeRTOS集成

磁力计是惯性导航与电子罗盘系统的核心传感器,其输出原始磁场数据需经精确采集、单位换算与误差补偿才能用于姿态解算。基于各向异性磁阻(AMR)原理的三轴磁力计,如HMC5883L,依赖稳定I²C通信获取12位有符号磁场采样值,并通过增益配置、硬软铁校准及温度补偿提升物理量精度。在嵌入式实时系统中,驱动层须保障数据的时间一致性与抗干扰鲁棒性,避免总线挂死、字节错位或量程误配等典型问题。本文围绕HMC5883L这一广泛使用的停产但仍在产线服役的磁传感器,详解寄存器配置、定点单位转换、八方位校准算法及FreeRTOS

weixin_42594427的博客 145

请尽可能地详细说明一个VLA项目的立项训练到落地的全流程

一个机器人VLA项目的全流程是一个复杂的系统工程,它深度融合了机器人学 (Robotics)计算机视觉 (CV)和自然语言处理 (NLP)。其核心挑战在于高质量数据的获取和从仿真到现实的有效迁移。与纯粹的软件AI项目相比,它增加了硬件、物理交互和安全性的维度,但其最终能让AI走出虚拟世界、在物理世界中产生实际价值,这也是其巨大的魅力所在。

具身机器人和通用AI 303

spring 事务管理失效原因

为什么80%的码农都做不了架构师?>>> ...

weixin_34050427的博客 173

Unity 横版游戏开发天花板?状态机、联机同步与横版动作游戏架构全都有

在 Unity 横版动作游戏开发领域,最耗时间的往往不是角色移动,而是整套“可扩展架构”的搭建。包括角色状态管理、敌人 AI、武器系统、关卡编辑器、联机同步、输入适配、UI 与存档系统等。2D Action Platformer Kit 的核心价值,并不只是“提供素材”,而是它已经帮开发者搭好了一整套适用于横版动作游戏的底层框架。

2403_88403568的博客 425

spring 第一期:@Transactional 下的事务管理以及该注解失效的常见原因

1.回顾一下事务 事务Transaction,它是一些严密操作的集合,要么都操作完成,要么都回滚撤销,事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。    (1)原子性(Atomicity)     事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。   (2)一致性(C...

Swing 3979

微软商店报错“此产品当前不可用”?终极修复指南

微软商店报错“此产品当前不可用”?终极修复指南

安德洛夫 3812

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

spring事务管理器的作用_Spring事务失效原因及解决方法

spring 提供事务功能需要依赖于数据库的事务支持。而数据库层的事务提交和回滚是通过bin log 或者 redo log 实现的。大部分情况下我们使用基于 @Transactional 注解的声明式事务。声明式事务本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。对于Spring事...

weixin_39878991的博客 540

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spring注解事务失效原因

整理了一下Spring事务失效的原因,希望帮到有缘人。 原因一:没有开启事务管理 原因二:标注了@Transactional的方法里面的异常被捕获了 原因三:标注了@Transactional的方法发生了非Error 或者 非RuntimeException 原因四:标注了@Transactional的方法的事务传播类型propagation配置成了NOTSUPPORT 原因五:标注了@Transactional的方法的事务传播类型propagation配置成了NEVER 原因六:标注了@Transact

morrison1的博客 3426

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

spring声明式事务失效

aa

秋楓的博客 796

Spring 事务失效的7种场景

目录 1、事务失效的7种情况 1.1、未启用 spring 事务管理功能 1.2、方法不是 public 类型的 1.3、数据源未配置事务管理器 1.4、自身调用问题 1.5、异常类型错误 1.6、异常被吞了 1.7、业务和spring事务代码必须在一个线程中 2、如何快速定位事务相关bug? 1、事务失效的7种情况 1.1、未启用 spring 事务管理功能 @EnableTransactionManagement 注解用来启用 spring 事务自动管理事务的功能,这个注解.

javaTalk 567

老生常谈 - 引起Spring事务失效的几种情况总结

文章目录前言常见的Spring事务失效原因没有被Spring管理发生自调用方法不是public的数据源未配置事务管理器数据库引擎不支持事务事务传播机制设置以不支持事务运行异常被catch掉了异常类型错误总结 前言     在使用Spring的事务管理时,有时候就会莫名其妙的发现事务没生效,其实并非Spring事务管理本身的问题,而是开发人员在使用时使用方式不对,Spring事务管理的底层机制没搞懂,又或者数据库层的问题导致,今天总结下Spring事务是失效的集中场景。 常见的Spring

qq_31279701的博客 693

关于spring中使用mysql数据库明明配置了事务管理却失效的原因及解决方法

直接点:你mysql数据库是否使用的MyISAM存储引擎?是的话,恭喜你:原因就是因为MyISAM引擎是不支持事务的 有人跟我说Spring+mybatis事务回滚无效。刚刚开始我以为是他事务配置或者AOP切面定义有问题!谁知道,查了很久原因,最后才知道,居然是因为他使用的mysql而且还用的Mysql的MyISAM引擎。 所以,以后如果还有人问你无法管理事务的问题,如果他还是用的Mysql,就先问他用的数据库存储引擎是什么吧,谢谢,使用mysql,只有InnoDB存储引擎支持事务处理 ...

wh445306 417

spring事务失效原因

spring事务失效

weixin_43866228的博客 529

Spring事务失效的几种场景及原因

Spring事务失效

qq_37518862的博客 3337

Spring事务失效原因

Spring事务管理主要有编程式和声明式两种方式,声明式事务管理更为常用。事务失效的原因包括方法非public、异常未正确抛出、自调用问题、传播行为配置不当、数据库引擎不支持事务、事务管理器配置错误、多线程环境以及注解被错误覆盖等。

m0_61600773的博客 248
上一篇: Java常用8大排序算法+二分法查找法
下一篇: 如何打一手好Log
andybbc
博客等级 码龄11年 64粉丝 93原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值