事务是什么?了解事务的原理吗?说下Spring的事务原理,能自己实现Spring事务原理吗?先自我检测下这些知识掌握了吗。那么接下来一起看下与Spring相关的事务
事务具有ACID特性。
是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
Spring事务的底层依赖MySQL的事务,代码层面上利用AOP实现。MySQL的事务有隔离级别的概念,只有InnoDB有事务,并且实现方式是利用undo log和redo log。
AOP方面,有连接点,切点,增强,目标,织入。参考Spring AOP入门,Spring则是在代码层面执行事务的时候使用TransactionInceptor进行拦截,然后处理。
系统解析Spring事务原理文章:
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)有我们根据条件进行是否要拦截的数据,根据参数就可以判断。
可以跟进去DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法中看
PointcutAdvisor为BeanFactoryTransactionAttributeSourceAdvisor MethodMatcher为TransactionAttributeSourcePointcut 复制代码
得到的拦截器为事务拦截器,既然是事务拦截器,那么可以跟上之前的分析了。
Spring事务原理分析
而Advice是advisor中的,advisor是BeanFactoryTransactionAttributeSourceAdvisor
然后调用computeTransactionAttribute(method, targetClass),判断是否有事务属性
AbstractFallbackTransactionAttributeSource.computeTransactionAttribute --> AnnotationTransactionAttributeSource.determineTransactionAttribute 获取方法属性 --> 获取到TransactionAttribute,然后返回 复制代码
最后一个就是在当前的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+")"); } 复制代码
答:
一般加上有@Transactional注解的bean,默认都会创建为代理的bean,在调用save方法的时候,因为save方法没有加上注解,所以save方法不会被方法拦截器进行拦截。那么调用的时候走的就是正常的调用save方法了。
直接调用insert方法,因为insert有注解,是会被拦截的属于正常的情况,不用过多的解释。
另外方法之所以被拦截是因为有代码逻辑控制,在执行insert之前会判断要不要进行拦截,save方法也是一样的。 直接调用save方法
-> 发现save方法没有增强,不会被拦截
-> 激发调用save方法,此时在save方法的逻辑代码内
-> 直接走进insert方法,而没有对insert进行是否要拦截判断
再说下直接调用insert的是正常情况,会判断是否要拦截,然后事务就会生效了。