外观
事务什么场景下会失效
⭐ 题目日期:
美团 - 2025/4/4
📝 题解:
事务失效的常见场景通常与事务管理配置、代码设计或运行时环境有关,以下是具体场景及原因分析:
1. 未启用事务管理
- 场景:未在 Spring 配置中启用事务管理(如忘记
@EnableTransactionManagement
)。 - 解决:确保配置类或 XML 中启用了事务管理。
2. 数据库/存储引擎不支持事务
- 场景:使用不支持事务的存储引擎(如 MySQL 的
MyISAM
)。 - 解决:切换为支持事务的引擎(如
InnoDB
)。
3. 异常未被正确抛出
- 场景:
- 默认情况下,Spring 事务仅在抛出 非检查型异常(如
RuntimeException
)时回滚。 - 若方法捕获异常未重新抛出,或仅抛出检查型异常(如
Exception
),事务不会回滚。
- 默认情况下,Spring 事务仅在抛出 非检查型异常(如
- 示例:
@Transactional public void method() { try { // 数据库操作 } catch (Exception e) { // 捕获异常未抛出 → 事务不回滚 } }
- 解决:
- 使用
@Transactional(rollbackFor = Exception.class)
指定回滚的异常类型。 - 在
catch
中抛出RuntimeException
或调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
。
- 使用
4. 非 Public 方法
- 场景:
@Transactional
注解标注在非public
方法上。 - 原因:Spring AOP 无法代理非
public
方法。 - 解决:将方法改为
public
。
5. 自调用问题
- 场景:同一类中的方法直接调用
@Transactional
方法。public class ServiceA { public void methodA() { methodB(); // 直接调用 → 事务失效 } @Transactional public void methodB() { /* 操作 */ } }
- 原因:自调用绕过代理对象,事务拦截器未生效。
- 解决:
- 通过注入自身代理对象调用(需启用
@EnableAspectJAutoProxy(exposeProxy = true)
)。 - 将方法拆分到不同类中。
- 通过注入自身代理对象调用(需启用
6. 事务传播机制配置错误
- 场景:传播行为配置不当(如
REQUIRES_NEW
未生效)。 - 示例:
@Transactional(propagation = Propagation.REQUIRED) public void methodA() { methodB(); // 预期开启新事务,但因配置错误未生效 } @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB() { /* 操作 */ }
- 解决:检查传播行为配置,确保方法调用通过代理对象。
7. 多数据源未指定事务管理器
- 场景:项目中使用多个数据源,但未明确指定事务管理器。
- 解决:在
@Transactional
中指定transactionManager
属性:@Transactional(value = "customTransactionManager")
8. 事务超时或只读设置冲突
- 场景:
@Transactional(timeout = 1)
设置过短,导致事务超时回滚。@Transactional(readOnly = true)
下执行写操作。
- 解决:调整超时时间或移除
readOnly
限制。
9. 异步方法未启用事务
- 场景:在
@Async
方法中使用事务,未配置事务传播。 - 解决:确保异步任务使用支持事务的线程池(如
TransactionalTaskExecutor
)。
10. 手动提交干扰
- 场景:在代码中手动调用
commit()
或rollback()
(如直接使用DataSourceTransactionManager
)。 - 解决:避免混合使用声明式事务和手动事务控制。
排查步骤
- 检查
@Transactional
注解是否生效(如方法是否为public
)。 - 确认事务管理器已正确配置。
- 检查异常是否按预期抛出。
- 使用调试工具(如
TransactionSynchronizationManager.isActualTransactionActive()
)验证事务是否激活。 - 查看日志中的事务生命周期(开启、提交、回滚)。
通过以上场景分析,可以快速定位事务失效的根本原因。