写点什么

【深入解剖 Spring 事务管理】原理、传播机制与 12 大失效场景避坑指南

  • 2025-07-24
    福建
  • 本文字数:1983 字

    阅读完需:约 7 分钟

Spring 事务管理是构建健壮企业应用的核心,其核心原理、@Transactional注解的工作机制、传播行为及失效场景是开发者必须掌握的关键点。下面我将逐一深入解析:


一、Spring 事务管理的核心原理

Spring 事务的本质是 通过 AOP(面向切面编程) 对目标方法进行增强,具体流程如下:


1、代理对象创建

  • 当使用 @Transactional 注解时,Spring 会为目标 Bean(如 UserServiceImpl)创建代理对象(JDK 动态代理或 CGLIB 代理)。

  • 调用 userService.updateUser() 时,实际调用的是代理对象的方法。


2、事务拦截器(TransactionInterceptor)

  • 代理对象内部包含一个 TransactionInterceptor

  • 在目标方法执行前,拦截器通过 PlatformTransactionManager(如 DataSourceTransactionManager)开启事务(获取数据库连接,设置 autoCommit=false)。


3、目标方法执行

  • 执行原始方法逻辑(包含数据库操作)。


4、事务提交/回滚

  • 方法成功执行 → 提交事务(connection.commit())。

  • 抛出未捕获的异常 → 回滚事务(connection.rollback())。


// 伪代码:TransactionInterceptor 逻辑public Object invoke(MethodInvocation invocation) {    TransactionStatus status = transactionManager.beginTransaction(); // 开启事务    try {        Object result = invocation.proceed(); // 执行目标方法        transactionManager.commit(status);    // 提交事务        return result;    } catch (RuntimeException e) {        transactionManager.rollback(status);   // 回滚事务        throw e;    }}
复制代码


二、@Transactional 注解工作机制


1、注解解析

  • Spring 扫描 Bean 时识别 @Transactional,为类或方法生成代理。

  • 注解属性(如 propagationisolationrollbackFor)被解析为 TransactionAttribute


2、事务属性绑定

  • 方法执行时,TransactionInterceptor 根据注解属性配置事务行为(如传播机制、隔离级别)。


3、事务管理器协调

  • 通过 PlatformTransactionManager 管理事务生命周期(开启、提交、回滚)。


三、事务传播机制(Propagation Behavior)


定义多个事务方法相互调用时的事务边界规则,共 7 种类型:



经典场景对比


@Servicepublic class OrderService {    @Transactional(propagation = Propagation.REQUIRED)    public void createOrder() {        // 主订单逻辑        orderItemService.addItem(); // 调用子事务方法    }}
@Servicepublic class OrderItemService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void addItem() { // 订单项逻辑(独立事务,失败不影响主订单) }}
复制代码


四、事务失效的 12 个常见场景


1、非 public 方法

  • 原因:Spring AOP 无法代理私有方法(CGLIB 通过继承实现代理)。

  • 解决:将方法改为 public


2、自调用问题

  • 原因:类内部方法调用(如 this.update())不经过代理对象。

  • 解决:

@Autowired private UserService selfProxy; // 注入自身代理
public void save() { selfProxy.update(); // 通过代理调用}
复制代码


3、异常类型不匹配

  • 原因:默认只回滚 RuntimeException 和 Error,捕获 Exception 不会回滚。

  • 解决:明确指定回滚异常:

@Transactional(rollbackFor = Exception.class)
复制代码


4、手动捕获异常未抛出

  • 错误示例:

try {    userDao.insert();} catch (Exception e) {    // 未抛出 → 事务提交!}
复制代码


5、多线程调用

  • 原因:事务信息存储在 ThreadLocal,新线程无法获取上下文。

  • 解决:避免跨线程事务操作。


6、数据库引擎不支持事务

  • 如 MySQL 的 MyISAM 引擎不支持事务(需使用 InnoDB)。


7、未启用事务管理

  • 缺失注解:@EnableTransactionManagement(Spring Boot 中自动配置)。


8、Bean 未被 Spring 管理

  • 原因:类未标注 @Service/@Component


9、Checked Exception 未配置回滚

  • 原因:Checked Exception(如 IOException)默认不回滚。

  • 解决:显式配置 @Transactional(rollbackFor = IOException.class)


10、传播行为配置为 NOT_SUPPORTED/NEVER

  • 强制以非事务方式运行。


11、方法内启动新线程异步操作

  • 异步操作脱离原事务上下文(需用 @Async + @Transactional 单独管理)。


12、嵌套事务回滚不当

  • 嵌套事务(NESTED)需外层捕获内层异常,否则整体回滚。


关键总结



最佳实践

  • 始终在 @Service 层的 public 方法上使用 @Transactional

  • 明确指定 rollbackFor(如 rollbackFor = Exception.class)。

  • 对嵌套事务使用 Propagation.NESTED 时,确保数据库驱动支持保存点(Savepoint)。

  • 避免在事务方法中处理耗时操作(如 RPC 调用),减少数据库连接占用时间。


理解这些机制能有效避免生产环境的事务陷阱,确保数据一致性。


文章转载自:佛祖让我来巡山

原文链接:https://www.cnblogs.com/sun-10387834/p/18995499

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
【深入解剖Spring事务管理】原理、传播机制与12大失效场景避坑指南_spring_不在线第一只蜗牛_InfoQ写作社区