SpringBoot事务失效的八大原因及解决方案

 更新时间:2025年09月05日 11:06:20   作者:IT 刘工  
在 Spring Boot 项目开发中,声明式事务管理通过 @Transactional 注解提供了极大的便利,但许多开发者都曾遇到过事务不生效的困扰,本文将详细分析导致 Spring Boot 事务失效的八大常见情况,并提供相应的解决方案,需要的朋友可以参考下

引言

在 Spring Boot 项目开发中,声明式事务管理通过 @Transactional 注解提供了极大的便利。

但许多开发者都曾遇到过事务不生效的困扰。

本文将详细分析导致 Spring Boot 事务失效的八大常见情况,并提供相应的解决方案。

1. 数据库引擎不支持事务

问题分析:这是最根本的原因。如果数据库存储引擎本身不支持事务(如 MySQL 的 MyISAM),那么无论 Spring 如何配置,事务都不会生效。

解决方案

  • 确保你的数据库表使用支持事务的引擎,如 MySQL 的 InnoDB
  • 建表时指定存储引擎:CREATE TABLE ... ENGINE=InnoDB;

2. 事务方法非 public 修饰

问题分析@Transactional 基于 Spring AOP 实现,而 AOP 代理默认无法拦截非 public 方法。

@Service
public class UserService {
    @Transactional // 失效!
    private void createUser(User user) {
        userMapper.insert(user);
    }
}

解决方案

  • 始终将 @Transactional 注解应用于 public 方法上

3. 自调用问题(Within-Class Invocation)

问题分析:这是最常见且最容易踩坑的原因。当一个类中的非事务方法调用同一个类中的 @Transactional 方法时,事务不会生效。

@Service
public class UserService {
    
    public void createUser(User user) {
        // 一些非事务操作
        this.insertUser(user); // 自调用,事务失效!
    }
    
    @Transactional
    public void insertUser(User user) {
        userMapper.insert(user);
        // 如果这里出现异常,事务不会回滚
    }
}

解决方案

  • 推荐方案:将事务方法抽取到另一个 Service 类中
  • 通过 ApplicationContext 获取代理对象调用(不优雅)
  • 使用 AspectJ 模式的事务管理(配置复杂)

4. 异常类型不正确或被捕获

问题分析@Transactional 默认只在抛出运行时异常(RuntimeException)和 Error 时回滚。

@Transactional
public void method() throws Exception {
    // 数据库操作
    throw new Exception("受检异常"); // 事务不会回滚!
}

另一个陷阱:异常被捕获但未重新抛出

@Transactional
public void method() {
    try {
        int i = 1 / 0; // 抛出 RuntimeException
    } catch (Exception e) {
        e.printStackTrace(); // 只是打印,事务不会回滚!
    }
}

解决方案

  • 使用 rollbackFor 属性指定回滚的异常类型:
@Transactional(rollbackFor = Exception.class)
  • 在 catch 块中重新抛出运行时异常

5. 传播行为(Propagation)设置不当

问题分析:错误配置传播行为会导致意外结果。

@Transactional(propagation = Propagation.NOT_SUPPORTED) // 不以事务运行
public void method() {
    // 这里没有事务
}

解决方案

  • 根据业务需求正确配置传播行为
  • 理解各种传播行为的含义:
    • REQUIRED(默认):支持当前事务,不存在则新建
    • REQUIRES_NEW:新建事务,挂起当前事务
    • NOT_SUPPORTED:非事务方式执行
    • NEVER:非事务方式执行,存在事务则抛出异常

6. 未被 Spring 容器管理

问题分析:如果类没有加上 @Service, @Component 等注解,它就不是 Spring Bean,其上的 @Transactional 注解不会被扫描。

// 缺少 @Service 注解
public class UserService {
    @Transactional // 失效!
    public void createUser(User user) {
        // ...
    }
}

解决方案

  • 确保类被 Spring 管理,添加适当的注解

7. 多线程环境下调用

问题分析:事务信息存储在 ThreadLocal 中,新线程中的操作不属于原事务。

@Transactional
public void method() {
    new Thread(() -> {
        userMapper.insert(user); // 不在事务中!
    }).start();
}

解决方案

  • 避免在事务方法中创建异步线程进行数据库操作
  • 使用分布式事务解决方案处理跨线程事务

8. 配置问题

问题分析

  • 未开启事务管理(虽然 Spring Boot 会自动配置)
  • 多数据源未正确配置事务管理器

解决方案

  • 确保配置了 @EnableTransactionManagement(Spring Boot 通常自动配置)
  • 多数据源时为每个数据源配置对应的事务管理器:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}
  • 使用 @Transactional(value = "txManagerName") 指定事务管理器

事务调试技巧

开启事务调试日志,在 application.properties 中添加:

logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG

这将帮助你看清事务何时开启、回滚或提交。

总结

Spring Boot 事务失效通常由以上八大原因导致,其中自调用问题最为常见。要确保事务正常工作,需要:

  1. 使用支持事务的数据库引擎(如 InnoDB)
  2. @Transactional 应用于 public 方法
  3. 避免自调用,将事务方法放在不同类中
  4. 正确处理异常,确保异常能够触发回滚
  5. 正确配置传播行为
  6. 确保 Bean 被 Spring 管理
  7. 避免多线程事务问题
  8. 检查事务相关配置

希望本文能帮助你有效解决 Spring Boot 中的事务失效问题。

以上就是SpringBoot事务失效的八大原因及解决方案的详细内容,更多关于SpringBoot事务失效原因及解决的资料请关注脚本之家其它相关文章!

相关文章

  • 关于JSON.toJSONString()和Gson.toJson()方法的比较

    关于JSON.toJSONString()和Gson.toJson()方法的比较

    本文介绍了两种将Java对象转换为JSON字符串的方法:阿里的`JSON.toJSONString()`和谷歌的`Gson.toJson()`,通过一个示例,展示了当使用继承关系且子类覆盖父类字段时,`Gson`会报错,而`JSON`可以正常运行,作者建议在处理JSON相关操作时使用阿里的`JSON`类
    2024-11-11
  • Java EasyExcel读写excel如何解决poi读取大文件内存溢出问题

    Java EasyExcel读写excel如何解决poi读取大文件内存溢出问题

    这篇文章主要介绍了Java EasyExcel读写excel如何解决poi读取大文件内存溢出问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • Mybatis-Plus中分页插件PaginationInterceptor的使用

    Mybatis-Plus中分页插件PaginationInterceptor的使用

    我们在开发的过程中,经常会遇到分页操作,本文主要介绍了Mybatis-Plus中分页插件PaginationInterceptor的使用,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Spring Boot 中整合 MyBatis-Plus详细步骤(最新推荐)

    Spring Boot 中整合 MyBatis-Plus详细步骤(最新推荐)

    本文详细介绍了如何在SpringBoot项目中整合MyBatis-Plus,包括整合步骤、基本CRUD操作、分页查询、批量操作、自定义SQL操作等,通过这些步骤,开发者可以快速实现数据库操作,提高开发效率,感兴趣的朋友一起看看吧
    2025-01-01
  • 浅析Java中ConcurrentHashMap的存储流程

    浅析Java中ConcurrentHashMap的存储流程

    ConcurrentHashMap技术在互联网技术使用如此广泛,几乎所有的后端技术面试官都要在ConcurrentHashMap技术的使用和原理方面对小伙伴们进行360°的刁难,本文详细给大家介绍一下ConcurrentHashMap的存储流程,需要的朋友可以参考下
    2023-05-05
  • Springboot-dubbo-fescar 阿里分布式事务的实现方法

    Springboot-dubbo-fescar 阿里分布式事务的实现方法

    这篇文章主要介绍了Springboot-dubbo-fescar 阿里分布式事务的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • Java 图片压缩实现思路及代码

    Java 图片压缩实现思路及代码

    本文为大家详细介绍下图片压缩的具体实现思路及java代码,想学习的各位可以参考下哈,希望对大家有所帮助
    2013-07-07
  • 深入浅析Mybatis与Hibernate的区别与用途

    深入浅析Mybatis与Hibernate的区别与用途

    这篇文章主要介绍了Mybatis与Hibernate的区别与用途的相关资料,需要的朋友可以参考下
    2017-10-10
  • IntelliJ IDEA 2017.1.4 x64配置步骤(介绍)

    IntelliJ IDEA 2017.1.4 x64配置步骤(介绍)

    下面小编就为大家带来一篇IntelliJ IDEA 2017.1.4 x64配置步骤(介绍)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Java中Set与List的关系与区别介绍

    Java中Set与List的关系与区别介绍

    这篇文章主要介绍了Java中Set与List的关系与区别介绍,本文总结它们两个接口都是继承自Collection、它们之间的存储方式不一样,需要的朋友可以参考下
    2015-03-03

最新评论