本地事务失效的情况

[复制链接]
发表于 2025-3-16 14:37:00 | 显示全部楼层 |阅读模式

本地事务失效的常见情况主要有以下几种:

  1. 非 public 方法
    Spring 默认使用 AOP 代理,@Transactional 注解在非 public 方法上不生效。需确保事务方法为 public

  2. 自调用问题
    同一类中的非事务方法调用事务方法(如 a() 调用 @Transactionalb()),因代理对象被绕过,事务不生效。应通过代理对象调用或拆分类。

  3. 异常处理不当

    • 未抛出异常:默认事务回滚仅对 RuntimeExceptionError 生效。若抛出检查异常(如 IOException),需通过 @Transactional(rollbackFor = ...) 显式配置。
    • 异常被捕获:在方法内 try-catch 异常但未重新抛出,事务管理器无法感知异常,不会回滚。
  4. 传播行为配置错误
    若事务传播行为设置为 SUPPORTSNOT_SUPPORTEDNEVER,且当前无事务上下文,方法将以非事务方式运行。

  5. 数据库引擎不支持事务
    如 MySQL 的 MyISAM 引擎不支持事务,需使用 InnoDB。

  6. 未配置事务管理器
    Spring 容器中未声明 PlatformTransactionManager Bean,导致事务注解失效。

  7. 数据源自动提交未关闭
    若数据源配置为自动提交(auto-commit=true),每个 SQL 单独提交,事务无法回滚。

  8. 多线程环境
    事务上下文通常绑定于线程,跨线程操作会导致事务传播失效。

  9. 未通过 Spring 管理
    调用未被 Spring 代理的类中的 @Transactional 方法(如直接 new 对象),事务不生效。

  10. 代理模式限制
    使用 JDK 动态代理时,非接口方法的事务可能失效,需改用 CGLIB 代理(通过 @EnableTransactionManagement(proxyTargetClass = true))。

总结示例

// 自调用问题示例
public class ServiceA {
    public void methodA() {
        methodB(); // 自调用,事务失效
    }
    @Transactional
    public void methodB() { /* 操作数据库 */ }
}

// 异常处理不当示例
@Transactional
public void method() {
    try {
        // 数据库操作
    } catch (Exception e) {
        // 未抛出异常,事务不回滚
    }
}

解决方案

  • 确保事务方法为 public
  • 避免自调用,或通过 AopContext.currentProxy() 获取代理对象。
  • 合理配置 rollbackFor 和传播行为。
  • 检查数据库引擎及事务管理器配置。
  • 关闭数据源自动提交,统一由事务管理。

GMT+8, 2025-4-19 08:50 , Processed in 0.066583 second(s), 35 queries Archiver|手机版|小黑屋|Attic ( 京ICP备2020048627号 )

快速回复 返回顶部 返回列表