Spring事务失效的常见陷阱与解决方案 - 风风资源网
  • 首页
  • 网站源码
  • 软件仓库
  • 技术分享
    • 代码教程
  • 主题插件
  • 资源资讯
  • 值得一看
    • 写真套图

导航菜单
  • 首页
  • 网站源码
  • 软件仓库
  • 技术分享
    • 代码教程
  • 主题插件
  • 资源资讯
  • 值得一看
    • 写真套图

Spring事务失效的常见陷阱与解决方案

2025/12/3 小玖云  代码教程 67 0

本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。

原理

Spring事务的原理是:通过AOP切面的方式实现的,也就是通过代理模式去实现事务增强。

具体过程是:对包含@Transactional注解的方法进行拦截,然后重写,重新在方法里加入异常回滚的逻辑。而且,每个线程都是独立管理自己的事务,相互隔离。

原理简单,使用起来也简单,也就是在方法上打上@Transactional注解,然后事务就正常生效了。也很少有人去验证异常情况下是否能真正的回滚。

Spring事务让我熟悉的地方是哪哪看起来都简单,让我陌生的地方使用时的变种较多,有时候莫名其妙的不生效。

源码

以上原理的相关源码如下:


实践出真知

有时候在编码过程中,我会发现某些场景下的事务会失效,总有一些意想不到的情况和隐藏的坑等着你去发现。 我认为验证事务的最佳方法就是:记住基本原则 + 动手实践。记住基本原则能帮助你快速解决常规问题,而动手实践则能验证那些不常见或不确定的问题。

几种事务不生效的用法

以下是几种常见的Spring事务失效的情况,读者们一定要牢记。这不仅对日常编码非常有帮助,还能在面试时展示你的知识。

  • private方法

Spring是通过AOP代理的方式实现事务增强的,但是private方法无法被代理,所以在private方法上打@Transactional注解是不生效的。

  • final、static修饰的方法

和private方法类似,final和static修饰的方法也无法被代理,所以@Transactional注解也不生效。

因为,static是属于类方法,final修饰的方法无法被重写,自然也就无法植入事务增强代码。

  • Bean对象没有被Spring托管

某个类一定要被Spring托管,那才能通过@Transactional注解去增强事务。如果只有@Transactional注解,而没有把类交给Spring托管,事务也是不生效的。类似如下情况:

// 此处没有@Service注解,此类不被spring托管,及时有@Transactional也不生效
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public final void createAndUpdateUser() {
        createUser();
        updateUserById();
    }

    public void createUser() {
        User user = new User();
        user.setId(2L);
        user.setName("test2");
        user.setEmail("test2" + "@test.com");
        userMapper.insert(user);
        System.out.println("create user");
    }

    public void updateUserById() {
        User user = userMapper.findById(1L);
        user.setName("admin1");
        userMapper.update(user);
        int i = 1 / 0; // 此处会抛出异常
        System.out.println("update user");
    }
}
  • 异常被吞掉

如果在业务代码里,通过try……catch捕获了异常,同时又没有继续抛出异常时,Spring事务也是不生效的。

因为代理增强的逻辑就是要发现了异常,才能回滚事务。如果异常被方法本身吞掉了,则代理会认为没有异常,从而无法回滚。

  • 非RuntimeException异常

Spring事务默认会回滚RuntimeException 及其子类,以及 Error 类型的异常。如果是其余异常,则不会回滚。源码处可见:

这种非RuntimeException异常场景下,需要做2个动作从而保证事务回滚。

  1. 捕获异常,然后抛出自定义异常。
  2. 自行在@Transactional注解中增加@Transactional(rollbackFor = XxxxxxxException.class)属性。或者直接使用rollbackFor = Exception.class,也就免去了第一步。
  • 异步线程的场景

多个线程的场景下,只需要牢记每个线程只管理自己的事务即可。每个线程都有一个独立的事务上下文,存在ThreadLocal中,所以事务信息在不同线程之间是隔离的。

  • 重灾区:在同一个类中调用本类的方法

这个失效场景,是最容易出错的,而且变种还多。在同一个类中调用本类的方法时,牢记以下2点,即可破局:

  1. 是否会开启事务依赖此类的第一个被外部调用的方法。如果此类的第一个被外部调用的方法有@Transactional注解,那事务生效。
  2. 调用自己内部方法时,采用的是this.xxxMethod()的方式,这种方式是不会走AOP代理的,所以被调用的内部方法的@Transactional注解不生效。

如果确实需要调用内部方法,并且要事务生效的话,那只能将被调用的内部方法独立到新的类中,同时交给Spring管理。

一道面试题

以上关于事务不生效的用法都比较好记,只有在同一个类中调用本类的方法场景下存在多种变种。具体请看这道面试题。请问以下createAndUpdateUser方法的事务生效吗?

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public final void createAndUpdateUser() { //注意这里有final修饰
        createUser();
        updateUserById();
    }

    @Transactional
    public void createUser() {
        User user = new User();
        user.setId(2L);
        user.setName("test2");
        user.setEmail("test2" + "@test.com");
        userMapper.insert(user);
        System.out.println("create user");
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateUserById() {
        User user = userMapper.findById(1L);
        user.setName("admin1");
        userMapper.update(user);
        int i = 1 / 0; // 此处会抛出异常
        System.out.println("update user");
    }
}

如果按照重灾区:在同一个类中调用本类的方法里提到的2个原则,则事务全部生效。

如果按照final、static修饰的方法里提到的原则,则事务全部不生效。

那结果如何呢?结果是以上方法的事务全部生效。

为什么呢?这里在补充一个原则:final修饰的方法如果带上@Transactional注解,事务情况按照被调用的方法自身的事务托管情况而定。

因为以上代码中的createUser方法和updateUserById方法,都有@Transactional注解,所以都生效。

这种特殊情况也实在是让人瞠目,不过只需要牢记以上几种不生效的用法即可,谁没事儿写这种@Transactional + final的代码呢?除了面试会问……



点赞:0 分享 收藏

上一篇
雷电模拟器(64) v9.1.85.0绿色纯净版
下一篇
2025年全新随机美女视频源码带后台5.0版本_API接口功能
作者头像 作者名称 作者性别
小玖云
联系作者 作者主页

评论列表

取消回复

    •  
      Login

      小玖云

      站长 主页
      用户中心
      评论管理
      退出登陆
      • 204文章
      • 1评论
      • 2微语
  • 最新文章

      • 「艾西Aiwest」23套 COS作品写真合集[持续更新],元气少女精华作品
        • Isle-Editor (岛屿编辑器) - 免费开源 Web 富文本编辑器,也支持 Notion 块编辑、MarkDown 语法,官方支持 Vue3 开箱即用
          • Photor - 免费好用的截图美化在线工具,网页/软件等屏幕截图美化我一直在用它
            • Inspira UI - 免费开源、充满活力的 3D 视觉炸裂级动画组件库,支持 Vue3 集成,兼容 Nuxt.js
              • SLEA AI - 免费的 Logo 在线生成器,AI 生成的 Logo 水平吊打淘宝几千元的设计外包
                • WordPress屏蔽垃圾英文评论的方法
  • 热门文章

    • 全新二次元聚合短视频解析去水印系统源码 自适应双端
    • 油耗计算器费用记录查询HTML源码
    • EMLOG博客- 百度提交自动推送,判断文章是否收录
    • 视频打赏写真系统网站源码
    • 从 "礼拜鞋" 到全球爆款:惠东女鞋用 40 年走出的逆袭路
    • 淘宝扭蛋机盲盒抽中初音未来手办!这波欧气直接让二次元狂喜
  • 分类

    • 源码分享
    • 软件分享
    • 技术分享
    • 主题插件
    • 资源资讯
    • 值得一看
  • 网站统计 I 当前在线:1人

    • 本站管理:1位
    • 用户总数:1位
    • 置顶文章:0篇
    • 日志总数:204篇
    • 微语总数:2条
    • 评论总数:1条
    • 标签总数:471条
    • 页面总数:2页
    • 分类总数:8个
    • 链接总数:4条
    • 运行天数:0天
    • 最后更新:1月2日
  • Copyright © 2026风风资源网 程序:Emlog Pro powered by 风风资源网
    • 首页
    • Q 群
    • 搜索
    • 主题

    大家都在搜

    • ZFAKA发卡搭建教程
    • 打砖块游戏源码
    • 经典游戏植物大战僵尸
    • Notion块编辑
    • Coze
    • 404维护页面
    • 图标下载网站
    • 套图写真
    • lalaai人声分离
    • ZFAKA发卡系统源码
    • 文本数字统计
    • 截图美化在线工具
    • 免费Logo生成器
    • ZFAKA
    • 在线小游戏
    • LOGO在线生成器
    • 
    • 