标注@Transactional的方法执行逻辑是什么?为何需要创建代理?
Spring @Transactional注解核心问题解答
1. 标注@Transactional的方法执行时具体会发生什么?
注意只有标注在public方法、且由代理对象触发调用的情况下,事务逻辑才会执行,同类内部调用、private方法标注注解都会失效
当符合生效条件的@Transactional方法被调用时,完整流程如下:
- 调用实际走到Spring为目标类生成的AOP代理对象的对应方法,不会直接执行原类的业务逻辑
- 代理逻辑先读取注解上的配置参数,包括传播行为、隔离级别、超时时间、回滚异常类型、不回滚异常类型等
- 调用配置的事务管理器,根据传播规则判断是否需要新建事务:如果当前线程已经绑定了符合要求的事务,就直接复用该事务对应的数据库连接;否则新建一个事务,同时将新的数据库连接绑定到当前线程
- 执行开发者编写的目标业务方法
- 方法执行完成后根据执行结果做事务收尾:如果方法抛出了符合回滚规则的异常(默认仅对
RuntimeException和Error触发回滚),就执行事务回滚;其余情况都会执行事务提交 - 最后解除当前线程和数据库连接的绑定,归还连接到连接池,事务生命周期结束
2. @Transactional是不是仅在方法包含数据库操作时才会生效?
不是。
只要注解符合上述生效条件,不管方法内部有没有数据库操作,事务的完整控制流程都会正常执行:
- 哪怕方法是空实现,代理也会正常走获取数据库连接、开启事务、提交事务的流程,只是没有执行具体SQL而已,这种情况会无意义占用数据库连接资源,带来不必要的性能开销
- 如果方法内部只有非数据库操作(比如Redis、本地内存计算等),
@Transactional也会正常启动数据库事务,但对非数据库操作没有任何事务控制能力,属于无效配置
3. 创建代理的必要性是什么?
@Transactional属于声明式事务,核心是在不修改原有业务代码的前提下,给业务方法增加事务控制的增强逻辑,这一能力依赖Spring AOP实现,代理是Spring AOP的核心载体:
- 没有代理的情况下,直接调用原类的方法无法插入事务开启、提交、回滚的额外逻辑,也就无法实现声明式事务的无侵入特性
- Spring会根据目标类是否实现接口,自动选择JDK动态代理或CGLIB代理生成代理对象,两类代理的核心作用都是承载事务增强逻辑
- 我们常遇到的同类非事务方法调用事务方法不生效的问题,本质就是同类内调用走的是原类
this对象,不是代理对象,无法触发代理层的事务增强逻辑
内容的提问来源于stack exchange,提问作者Saniya Javed
相关产品推荐
相关产品推荐

