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

利用OTSU阈值算法在ZYNQ上实现浒苔识别

利用OTSU阈值算法进行图像二值化,结果用HDMI显示

qq_38075564的博客 1275

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

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

qq_45607784的博客 7755

C# 开发 WPS 插件实战:从环境搭建到功能实现(附完整代码)

本文提供了一份详尽的C#开发WPS插件实战指南,涵盖从环境搭建到功能实现的完整流程。通过COM技术,开发者可以创建自定义插件,为WPS Office扩展自动化功能,如文档处理与格式转换。文章包含核心概念解析、Ribbon界面集成、调试部署方法及完整代码示例,帮助开发者快速上手。

rust6ferris的博客 928

用Arduino和RC522模块DIY一个NFC门禁卡复制器(附完整代码)

本文详细介绍了如何利用Arduino和RC522模块DIY一个NFC门禁卡复制器,包括硬件连接、软件配置、数据读写技术及完整代码实现。通过本教程,电子爱好者可以深入了解NFC技术,并构建自己的智能门禁系统,适用于家庭安全、办公场所等多种场景。

weixin_33704591的博客 503

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

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

m0_68642284的博客 2300

瑞萨单片机-硬件I2C从设备

瑞萨单片机上实现I2C从机,根据主机发来的数据,从机返回或者保存数据2、R5F1115AxFL最多支持3个从设备地址(即可以作为三个从设备)3、从接收模式:直接将数据保存到RAM中,接收完再处理4、从发送模式:按照I2C读取传感器数据经验,主机读取从设备时,从设备需要立刻返回数据的,但是程序要如何实现一收到指令就返回特定的数据?(时钟拉伸)这里先跳过,我们先实现返回固定的数据。

qq_27893147的博客 3220

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

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

qq_42798343的博客 1343

Vivado ILA调试全攻略:从HDL实例化到Block Design的5个实战技巧

本文全面解析了Vivado集成逻辑分析仪(ILA)的五种核心调试方法,涵盖从HDL代码实例化到Block Design集成的实战技巧。详细对比了不同方法的优缺点与适用场景,并重点介绍了如何利用Debug Hub高效管理多时钟域复杂调试,旨在帮助FPGA开发者精准定位问题,显著提升板级调试效率。

weixin_29214199的博客 376

20、啁啾脉冲光纤放大器:原理、设计与仿真

本文详细介绍了啁啾脉冲光纤放大器(FCPA)的原理、设计与仿真过程。内容涵盖CPA技术的基本原理、光纤基CPA系统的组成、Tm掺杂光纤放大器的工作机制、全光纤脉冲展宽器的设计以及仿真分析。通过MATLAB仿真展示了脉冲在光纤中的展宽与放大过程,并讨论了如何优化系统以减少非线性失真、控制峰值功率并提高整体性能。文章还总结了系统优化的关键策略,并展望了未来的发展方向。

v4w5x6的博客 319

spring 事务管理失效原因

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

weixin_34050427的博客 173

第一百三十九回 介绍三个BLE包

本章回中主要介绍了Flutter中BLE的概念和操作方法,主要介绍了三个BLE包的功能和差异,以方便大家在BLE操作中选择不同的包。

talk_8的专栏 574

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

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

Swing 3979

Microsemi Libero系列教程(二)——新建点灯工程

前言 上一篇文章,介绍了Microsemi Libero系列教程(一)-Libero开发环境介绍,下载,安装与注册,作为嵌入式开发中的Hello World,点灯是再也基础不过的实验了,通过点灯实验,可以了解芯片GPIO的控制和开发环境IDE新建工程的流程,对于FPGA来说,每个IO口几乎一样,所以本篇文章主要学习一下如何基于Microsemi Libero集成开发环境建立一个示例工程,让一个L...

whik1194的博客 1万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

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

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

weixin_39878991的博客 540

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Spring注解事务失效原因

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

morrison1的博客 3426

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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、付费专栏及课程。

余额充值