一、 工作原理

@Transactional 的本质是基于 Spring AOP 实现的。当 Spring 容器启动时,它会扫描标注了该注解的类或方法,并为这些 Bean 生成一个 代理对象(Proxy)

执行流程

当调用方请求一个被 @Transactional 修饰的方法时,实际上是在调用代理对象。执行顺序如下:

  1. 拦截请求:代理对象拦截对目标方法的调用。
  2. 开启事务:代理对象向事务管理器(Transaction Manager)申请,通过数据库连接设置 conn.setAutoCommit(false)
  3. 执行业务:执行目标类中的实际业务方法。
  4. 结果处理
    • Commit:如果方法正常返回,代理对象执行事务提交。
    • Rollback:如果方法抛出特定异常,代理对象执行事务回滚。
  5. 资源清理:关闭数据库连接或将其归还连接池。

核心提示:理解“代理对象”是理解事务机制的关键。如果调用没有经过代理对象,事务逻辑就不会执行。

二、 核心属性详解

虽然 @Transactional 开箱即用,但在生产环境中,我们必须关注以下两个关键参数以确保数据一致性。

1. rollbackFor(回滚规则)

这是最容易被忽视的属性。

  • 默认行为:Spring 默认仅在抛出 RuntimeException(运行时异常)或 Error 时回滚。对于 Checked Exception(受检异常,如 IOExceptionSQLException),默认不回滚
  • 最佳实践:务必显式指定回滚异常类型,确保所有异常均能触发回滚。
1
2
3
4
5
// 推荐写法:覆盖所有异常情况
@Transactional(rollbackFor = Exception.class)
public void createUser() throws Exception {
// 业务逻辑
}

2. propagation(传播行为)

该属性定义了当事务方法被另一个事务方法调用时,事务该如何传播。Spring 共支持 7 种 传播行为:

属性值 行为描述 适用场景
REQUIRED (默认) 如果当前存在事务,则加入该事务;如果当前无事务,则新建一个事务。 绝大多数增删改业务场景
REQUIRES_NEW 无论当前是否存在事务,都挂起当前事务,开启一个独立的新事务。 记录日志、审计流水(即使主业务失败,日志也必须入库)
NESTED 如果当前存在事务,则在嵌套事务内执行(基于 JDBC SavePoint);如果无事务,行为同 REQUIRED。 复杂的子模块回滚需求(主事务回滚会回滚子事务,但子事务回滚不影响主事务)
SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。 纯查询操作(适合“能有最好,没有也行”的场景)
NOT_SUPPORTED 非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 发送邮件、短信等不涉及数据库的耗时操作,避免占用数据库连接
MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常 必须在已有事务上下文中执行的方法
NEVER 非事务方式执行,如果当前存在事务,则抛出异常 严禁在事务中执行的操作

总结

@Transactional 是一个强大的工具。深入理解其背后的 AOP 代理机制,并正确配置 回滚规则 (rollbackFor)传播行为 (propagation),是确保后端业务数据一致性的基础。