如何查看Spring中Transactional注解生成的代理代码及事务疑问
Spring @Transactional 动态代码查看与多线程事务问题解析
一、查看@Transactional动态生成的代理代码
- 用IDE调试直接查看:比如IntelliJ IDEA,给JVM添加参数
-Dspring.aop.proxy-target-class=true强制生成CGLIB代理(目标类为接口时用JDK动态代理),调试时找到代理对象,IDEA会自动反编译出代理类代码,能直接看到事务增强逻辑。 - 用字节码工具导出查看:添加JVM参数
-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true,运行程序后,动态代理类会被保存到项目根目录的com/sun/proxy(JDK代理)或对应包路径下(CGLIB代理),再用javap -c 代理类文件名命令反编译,就能看到生成的字节码对应的事务处理逻辑。
二、Spring给@Transactional方法插入的核心逻辑
Spring不会直接硬插entityManager.getTransaction().begin()这类代码,而是通过事务管理器统一管控,核心步骤如下:
- 方法执行前:
- 检查当前线程是否存在活跃事务(Spring用ThreadLocal存储事务上下文)
- 根据@Transactional的传播属性(如REQUIRED、REQUIRES_NEW等),决定复用现有事务或开启新事务
- 若开启新事务,通过事务管理器获取数据库连接,设置隔离级别、超时时间等参数后启动事务
- 方法执行过程中:
- 监听方法抛出的异常,根据@Transactional的rollbackFor/noRollbackFor配置,判断是否触发事务回滚
- 方法执行完成后:
- 如果事务是当前方法开启的,执行提交或回滚操作
- 释放数据库连接,清空线程本地的事务上下文
三、多线程环境下的EntityManager与Spring事务处理
首先明确:Spring默认注入的EntityManager是线程安全的,底层通过ThreadLocal实现线程隔离。
- Spring处理事务时,会将EntityManager实例绑定到当前线程的ThreadLocal中,每个线程获取到的都是独立的实例,不会出现多线程共用同一个EntityManager的情况。
- 你担心的“多个线程调用同一个entityManager.begin()抛异常”场景,在Spring标准用法里不会发生。
- 若手动创建EntityManager并在多线程间共享,确实会引发问题,但这不属于Spring的常规用法,Spring的ORM组件(如JpaTemplate)或@Autowired注入的EntityManager,都已做了线程隔离处理。
内容的提问来源于stack exchange,提问作者Cat
相关产品推荐
相关产品推荐

