Spring事务:@Transactional注解的一些记录

 

1,原理

Spring通过代理实现事务管理;

Java中代理分为静态代理和动态代理两种;

静态代理主要是aspectJ,在编译阶段将增强代码加入到字节码中;

动态代理有jdk动态代理和cglib两种;

Jdk动态代理是在运行过程中生成被代理类的子类,并将增强代码加入到方法中;

Cglib动态代理是在运行过程中实现被代理接口的实例,并将增强代码加入到方法中;

Spring采用的是动态代理而不是静态代理;

 

实际的事务方法注册流程:

容器启动时,创建bean;在AbstractBeanFactory的createBean方法中,会调用resolveBeforeInstantiation[Bean处理器],看是否需要产生代理对象;

resolveBeforeInstantiation中,调用applyBeanPostProcessorsAfterInitialization方法处理,会循环调用所有bean的后置处理器的postProcessAfterInitialization方法;

处理事务注解的后置处理器是AbstractAdvisingBeanPostProcessor,在该类的postProcessAfterInitialization中,我们直接看isEligible(bean, beanName)方法,继续调用AopUtils.canApply方法,看是否是由pointcut驱动的advisor,如果是,那么会调用MethodMatcher的matches方法;对于@Transactional注解来说,会由TransactionAttributeSourcePointcut这个实现类来做match的工作,最终会找到AbstractFallbackTransactionAttributeSource这个类中的getTransactionAttribute

方法来看是否使用到该注解,这里的核心方法是computeTransactionAttribute;

computeTransactionAttribute逻辑:首先检查该方法是否是public修饰的,然后看该注解是在方法上使用的还是在类上使用的;

 

2,使用

在需要事务的方法上或者类上加上@Transacional注解即可;

 

3,事务失效场景

首先定义接口 I1,I2;

定义I1的普通方法I1m1,事务方法I1t1;

定义I2的普通方法I2m1,事务方法I2t1;

1)I1m1调用I1t1时,I1m1不属于事务;

2)I1m1调用I1t1时,如果是直接this调用I1t1,那么I1t1也没有事务,因为spring需要注入接口才能管理事务

3)I1t1或者I2t1不是public修饰的,那么事务失效;

4)I1t1调用I2t1,并且try了I2t1的异常;如果I2t1抛异常了,并且I2t1没有catch异常,那么程序会抛出Transaction rolled back because it has been marked as rollback-only

异常;因为I2t1抛异常时候,spring会将其标记为回滚,然后I1t1提交commit的时候,发现I2t1有异常,所以导致不能正提交事务,随即抛出该异常。

上一篇:@Transactional 错误集锦以及如何正确使用


下一篇:声明式事务