Spring事务完全解析

事务是什么?了解事务的原理吗?说下Spring的事务原理,能自己实现Spring事务原理吗?先自我检测下这些知识掌握了吗。那么接下来一起看下与Spring相关的事务

概念

事务具有ACID特性。

是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

Spring事务的底层依赖MySQL的事务,代码层面上利用AOP实现。MySQL的事务有隔离级别的概念,只有InnoDB有事务,并且实现方式是利用undo log和redo log。

AOP方面,有连接点,切点,增强,目标,织入。参考Spring AOP入门,Spring则是在代码层面执行事务的时候使用TransactionInceptor进行拦截,然后处理。

系统解析Spring事务原理文章:

Spring AOP入门
Spring AOP增强(Advice)
Spring Bean生命周期
Spring AOP实现原理
Spring事务原理

代码

1.在AopConfigUtils可以看到具体会生成什么类型的AutoProxyCreator,这几个都是beanPostProcessor,在Bean创建之后对Bean的实例进行自定义处理。如果使用了@EnableTransactionManagement,经过一些配置这次生成的是InfrastructureAdvisorAutoProxyCreator,具体如何生成这个类的点进去@EnableTransactionManagement里面即可。

在这里插入图片描述

EnableTransactionManagement
-> @Import(TransactionManagementConfigurationSelector.class)
-> return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
-> AutoProxyRegistrar.registerBeanDefinitions中
-> 创建InfrastructureAdvisorAutoProxyCreator

在这里插入图片描述
在Bean的生命周期中,Bean创建完成调用创建InfrastructureAdvisorAutoProxyCreator.postProcessAfterInitialization方法。

另外AbstractAutowireCapableBeanFactory.initializeBean方法也值得一看

获取Bean的Advice,如果有Advice(增强的话),创建bean的动态代理。创建动态代理都是Spring AOP做的事情了,根据设置就是创建JDK动态代理和CGLib代理了,我们项目默认都是使用CGLib动态代理(proxyTargetClass=true即可),只说下CGlib的动态代理,主要利用了Enhancer类在这里插入图片描述
​ 这里有Enhacer用法Cglib的使用方法(1)–Enhancer

拦截接口intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)有我们根据条件进行是否要拦截的数据,根据参数就可以判断。

3.可以跟进去DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法中看

PointcutAdvisor为BeanFactoryTransactionAttributeSourceAdvisor
MethodMatcher为TransactionAttributeSourcePointcut

在这里插入图片描述
得到的拦截器为事务拦截器,既然是事务拦截器,那么可以跟上之前的分析了。

Spring事务原理分析

4.我们接着看为什么获取的拦截器是MethodInterceptor。在MethodMatcher.match中有AdvisorAdapter
在这里插入图片描述
而Advice是advisor中的,advisor是BeanFactoryTransactionAttributeSourceAdvisor

一种在TransactionProxyFactoryBean中默认的TransactionIntercetor
在这里插入图片描述
在默认的@EnableTransactionManagement注解中,将

BeanFactoryTransactionAttributeSourceAdvisor的advice设置为TransactionIntercetor,这一步的注解生效,我们第一步就已经讲过了
在这里插入图片描述
5.法是如何匹配的,TransactionAttributeSourcePointcut中matches方法,调用TransactionAttributeSource属性判断是否有method的属性
在这里插入图片描述
然后调用computeTransactionAttribute(method, targetClass),判断是否有事务属性

AbstractFallbackTransactionAttributeSource.computeTransactionAttribute
–> AnnotationTransactionAttributeSource.determineTransactionAttribute 获取方法属性
–> 获取到TransactionAttribute,然后返回

6.到现在我们基本上解释了,Spring的事务拦截器是如何生效的,拦截器什么时候设置的,事务方法是如何匹配的。

事务不生效

private方法不会生效,JDK中必须是接口,接口中不可能有private方法,而私有方法子类无法方法,也不会生效

CGLib代理的时候,final方法不会生效,抛NullPointException

protect方法的话,默认是只允许public方法。
在这里插入图片描述
最后一个就是在当前的bean中非事务方法调用事务方法为什么不生效?

public int save(String name, int age) throws Exception {
insert(name, age);
return 1;
}
@Transactional
public void insert(String name, int age){
jdbcTemplate.update(“insert into user(id,name,age)values(1,’”+name+"’,"+age+")");
jdbcTemplate.update(“insert into user(id,name,age)values(2,’”+name+"’,"+age+")");
jdbcTemplate.update(“insert into user(id,name,age)values(1,’”+name+"’,"+age+")");
}

答:

经过最终验证,得出如下结论:

如果先调用的save方法,在进行方法拦截的时候,方法拦截器首先获取当前动态代理的对象所代理的原始对象。
在这里插入图片描述
比如FirstApp生成的动态代理名称为FirstApp$CGlibxxx,这个时候通过getTarget获取的对象即为FirstApp的实例。

接下来如果判断当前的方法比如save方法没有Advice(增强),则直接调用原对象的方法,即这个时候调用的是FirstApp.save方法。而不是FirstApp$CGLibxxx的save方法。可以跟代码。

最后

Spring事务这块,如果认真看我写的文章,相信你会收获不少

猜你喜欢

转载自blog.csdn.net/zhuguang10/article/details/88575315