@Transactional 是元数据,真正开启和提交事务的是代理中的 TransactionInterceptor 与事务管理器。调用没有经过代理时,注解不会自动执行。
Table of contents
Open Table of contents
复现自调用失效
OrderService下载的外层方法调用同类 REQUIRES_NEW 方法:
mvn -Dtest=SpringSourceLabTest#selfInvocationDoesNotStartRequiresNewTransaction test
记录型事务管理器只看到一次 BEGIN 和 COMMIT,因为内部 this.audit() 没有再次经过代理。将不同事务边界拆到另一个 Bean,或使用编程式事务表达局部边界。
传播决定如何加入事务
| 传播 | 行为 |
|---|---|
REQUIRED | 有事务就加入,没有就新建 |
REQUIRES_NEW | 暂停外层并新建独立事务 |
NESTED | 使用保存点,依赖事务管理器支持 |
SUPPORTS | 有就加入,没有就非事务执行 |
REQUIRES_NEW 会额外占用数据库连接。外层持有一条连接、内层再取一条时,连接池容量不足可能死等。
隔离与回滚规则
隔离级别约束并发事务能观察到什么,最终行为还受数据库实现和 SQL 锁影响。默认继承底层数据库隔离,不应无证据地全局改为最高级别。
默认情况下 RuntimeException 和 Error 触发回滚,受检异常不回滚。捕获异常后正常返回会提交;需要回滚时重新抛出、声明 rollbackFor 或显式标记。
事务不会跨越所有边界
线程绑定事务不会自动传到新线程,HTTP/RPC 调用也不会共享本地数据库事务。远程一致性要用幂等、Outbox、Saga 或补偿,不要把数据库事务保持到网络调用结束。
Spring 官方事务注解说明明确指出默认代理模式只拦截外部调用。
下一步
阅读Spring MVC 启动映射与参数绑定,继续追踪 Web 请求进入控制器前的基础设施。