事务切面原理
(一)Xml开启事务
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
然后打开TxNamespaceHandler里面有个init方法调用
NamespaceHandlerSupport#registerBeanDefinitionParser给
AnnotationDrivenBeanDefinitionParser 注册进去了.这个类就是解析
AnnotationDrivenBeanDefinitionParser#parse 是解析
—————————
AnnotationDrivenBeanDefinitionParser的方法主要工作是注册了入口类,调用下面方法给AOP入口类注册
AnnotationDrivenBeanDefinitionParser#parse调用
AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer#configureAutoProxyCreator调用AopNamespaceUtils#registerAutoProxyCreatorIfNecessary
调用
AopConfigUtils#registerAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)调用
AopConfigUtils#registerOrEscalateApcAsRequired,然后给
InfrastructureAdvisorAutoProxyCreator
注册为事务AOP入口类,封装成BeanDefinition对象(因为Spring要对这些类进行实例化,所有就必须封装成BeanDefinition对象),但是这个AOP入口类是没用的.
——————————
(二)注解开启事务
@EnableTransactionManagement 开启事务,点进去
EnableTransactionManagement上面有@Import
TransactionManagementConfigurationSelector给这个类实例化,
其中TransactionManagementConfigurationSelector#selectImports方法在
其中ConfigurationClassParser#processImports调用到了selectImports方法,调用的内容是收集beanName,然后封装成beanDefinition对象进行实例化,
在ConfigurationClassBeanDefinitionReader#loadBeanDefinitions 变成BeanDefinition.
事务切面注册流程
如果一个类有@Transactional注解的话,那么这个类就会生成切面
在配置类上有个@EnableTransactionManagement注解,这个注解代表着开启了注解事务,然后通过@Import注解导入了
TransactionManagementConfigurationSelector类,
在TransactionManagementConfigurationSelector类里面的TransactionManagementConfigurationSelector#selectImports
方法ProxyTransactionManagementConfiguration类里面将事务切面和切入点注册进去了;
ProxyTransactionManagementConfiguration类逻辑
1. —————————-
ProxyTransactionManagementConfiguration#transactionAdvisor方法里面
实例化了BeanFactoryTransactionAttributeSourceAdvisor类,这个类就是事务切面类然后BeanFactoryTransactionAttributeSourceAdvisor设置了Advice(通知类)为
ProxyTransactionManagementConfiguration#transactionInterceptor(这个方法是创建事务advice),
transactionInterceptor逻辑
2. ——————
实例化了TransactionInterceptor对象同时设置了事务管理器(这个事务管理器是跟数据源挂钩的)和 AnnotationTransactionAttributeSource对象(AnnotationTransactionAttributeSource作用是解析@Transactional注解的一个类.)
2.——————
1.—————————-
事务切面执行流程
会在ReflectiveMethodInvocation#proceed 里面interceptorsAndDynamicMethodMatchers容器里面就有TransactionInterceptor
然后ReflectiveMethodInvocation#proceed 调用MethodInterceptor#invoke 会调用到子类的TransactionInterceptor#invoke就开始执行事务切面了.
然后调用TransactionAspectSupport#invokeWithinTransaction(invokeWithinTransaction方法就是具体的事务操作了,就是切面了)
在invokeWithinTransaction方法内部的逻辑:
1.———————————
获取事务属性类 AnnotationTransactionAttributeSource 如果为null,说明是非事务的
然后调用org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute获取TransactionAttribute
然后调用org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager获取事务管理器
然后调用org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary去创建事务
getTransactionAttribute内部逻辑是:
2.———————
调用org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute调用
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)调用
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute.调用完了获取到TransactionAttribute对象后放入
org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#attributeCache缓存里面提供下次不需要解析直接使用.
在determineTransactionAttribute内部逻辑
3.————————
循环解析org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#annotationParsers容器,(annotationParsers里面有
org.springframework.transaction.annotation.SpringTransactionAnnotationParser) ,去解析annotationParsers容器里面的SpringTransactionAnnotationParser, 其实就相当于解析@Transactional注解
然后调用org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)调用
org.springframework.transaction.annotation.SpringTransactionAnnotationParser
#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)
然后实例化了RuleBasedTransactionAttribute ,然后给@Transactional注解的属性塞入RuleBasedTransactionAttribute对象里面
3.———————
2. ——————-
determineTransactionManager内部逻辑是
2.2————————————
如果org.springframework.transaction.interceptor.TransactionAspectSupport#getTransactionManager获取不到PlatformTransactionManager就会调用
org.springframework.beans.factory.BeanFactory#getBean(java.lang.Class
如果还没有的话就报错.
其中TransactionManager 是从org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration#transactionInterceptor调用
org.springframework.transaction.interceptor.TransactionAspectSupport#setTransactionManager方法进行PlatformTransactionManager的赋值
2.2——————————-
createTransactionIfNecessary内部逻辑
2.3————————
最核心代码是org.springframework.transaction.PlatformTransactionManager#getTransaction调用子类AbstractPlatformTransactionManager#getTransaction 开启事务
其中getTransaction 内部逻辑:
3———————
调用org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction获取DataSourceTransactionObject
然后往下执行org.springframework.transaction.support.AbstractPlatformTransactionManager(DataSourceTransactionManager)#doBegin开启事务
doGetTransaction逻辑
4.—————-
实例化了DataSourceTransactionObject事务对象(管理connection对象,创建回滚点,按照回滚点回滚,释放回滚点)
调用org.springframework.jdbc.datasource.JdbcTransactionObjectSupport#setSavepointAllowed设置允许嵌套事务(默认是允许的,嵌套事务意思是默认是按照回滚 点回滚,也就是说不是全部回滚.)
然后调用org.springframework.transaction.support.TransactionSynchronizationManager#getResource,第一次调用的话获取的是空的,第二次调用的话,就是同一个 连接了,目的是为了适配@Transactional的 propagation(传播属性)属性的.比如说A方法调用B方法, A方法和B方法都有@Transactional,那么就可以根据 @Transactional的propagation属性配置来决定两个方法是一个事务还是不同的事务.
4.—————-
doBegin逻辑
4.2————————
如果没有连接就从连接池里面获取连接,然后封装成ConnectionHolder(连接池对象),然后又塞入DataSourceTransactionObject(事务对象),此时事务对象就有连接对 象,然后连接对象调用setAutoCommit(false)方法 (关闭连接的自动提交,其实这步就是开启了事务)
然后设置隔离级别(属性是从@Transactional注解解析的TransactionAttribute对象里面获取的)
然后设置状态事务状态,因为数据库资源是很宝贵的事务开启了就设置事务状态.
如果在这个事务只有查询的话,就可以设置为只读事务(这样效率会加大,因为只读事务在数据库里面会少了很多锁的操作.)
然后调用org.springframework.jdbc.datasource.DataSourceTransactionManager.DataSourceTransactionObject#isNewConnectionHolder如果成立说明是当前线程 第一次访问,就调用 org.springframework.transaction.support.TransactionSynchronizationManager#bindResource给数据源和CollectionHolder放入
org.springframework.transaction.support.TransactionSynchronizationManager#resources(ThreadLocal容器里面),当前线程第二次操作事务的时候就会从这个 resources容器里面获取连接资源信息等等,
4.2————————
3———————
2.3————————
1. ——————————-
两个方法两个事务同一事务对象
A方法调用B方法, A和B都有@Transactional 注解,默认情况下 A和B是一个事务对象.
调用下面方法全部都会走两次
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction调用
org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary 开启事务,然后调用
然后会走org.springframework.transaction.PlatformTransactionManager#getTransaction 调用
org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction调用
org.springframework.transaction.support.TransactionSynchronizationManager#getResource方法获取ConnectionHolder对象,如果是第一次,ConnectionHolder是null(因为还没有创建事务),
org.springframework.transaction.support.TransactionSynchronizationManager#getResource逻辑
1. ———————
调用org.springframework.transaction.support.TransactionSynchronizationUtils#unwrapResourceIfNecessary看看数据源连接池有没有扩展,一般没有,
然后调用org.springframework.transaction.support.TransactionSynchronizationManager#doGetResource
doGetResource逻辑
2. ————————
先从org.springframework.transaction.support.TransactionSynchronizationManager#resources(resources是一个ThreadLocal)这个对象里面获取建立的连接池对象和连接对象的映射,如果当前访问线程第一次进来的话,resources容器里面肯定没有东西,就直接返回null.如果不是第一次进来的话,就可以直接从resources容器里面获取到这个线程上次访问时候存到里面的 建立的连接池对象和连接对象的映射.
2.————————
1.———————
在执行事务切面的时候流程
如果一个类有@Transactional注解的话,那么这个类就会生成切面,在执行有@Transactional方法的时候就会执行到
org.springframework.transaction.interceptor.TransactionInterceptor的invoke方法
然后调用org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction方法
invokeWithinTransaction逻辑
1————————————-
在这里开启事务,或者提交事务,或者回滚事务.
1————————————-
事务状态TransactionStatus
org.springframework.transaction.TransactionStatus
事务状态是记录事务在运行时的一些特征的,比如说事务是否是最新的事务.
| @Transactional(propagation = Propagation.REQUIRED)
@Override
public void transation(ConsultConfigArea area, ZgGoods zgGoods_) {
_areaService.addArea(area);
goodsService.addGoods(zgGoods);
}//*@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public int addArea(ConsultConfigArea area_) {
_int i = commonMapper.addArea(area);
return i;
} |
| —- |
什么是最新事务,比如说transation方法就是最新事务,transation调用了addArea方法,虽然采用默认的传播属性,虽然是同一个连接,但是事务对象是不一样的.
底层源码在调用org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction的时候会实例化一个新的DataSourceTransactionObject对象(每次执行doGetTransaction方法的时候都会实例化新的).
DataSourceTransactionObject (事务对象)封装了数据库连接对象,第一次是新的连接,
在第二次进入doGetTransaction方法的时候,会从ThreadLocal获取上一个事务的连接对象.
事务类说明
(一)AnnotationTransactionAttributeSource
AnnotationTransactionAttributeSource作用是解析@Transactional注解的一个类.
(二)TransactionAttribute
TransactionAttribute是封装@Transactional里面的属性的,比如说rollbackFor,readOnly等等. 我觉得是类似于matedata的一个东西.
(三)RuleBasedTransactionAttribute
RuleBasedTransactionAttribute 封装了事务的隔离级别,传播属性等等.是否只读事务,异常等等.
(四)DataSourceTransactionObject
是事务对象,是管理的连接对象 里面包装了ConnectionHolder
1.ConnectionHolder
ConnectionHolder包装了java.sql.Connection对象