Spring源码(八):Spring事务详解

一、事务执行流程

  1. 开启事务
  2. 执行DML语句
  3. 提交事务/回滚事务

说明:如果多个DML语句是同一个连接对象操作的,他们的算作同一个事务,前提是关闭自动提交。

二、Spring事务切面

        事务切面开启注解@EnableTransactionManagement,由注解上的@Import(TransactionManagementConfigurationSelector.class)来到selectImports方法。PROXY代表JDK事务,引入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration。
在这里插入图片描述
        AutoProxyRegistrar的作用是注册aop的入口类InfrastructureAdvisorAutoProxyCreator,把属性设置到入口类中,最终会copy到proxyFactory中。Bean实例化最后一步判断是否有切面,如果有则生成代理。
在这里插入图片描述
        ProxyTransactionManagementConfiguration中定义了事务切面BeanFactoryTransactionAttributeSourceAdvisor。
        首先在事务切面里面设置处理事务属性对象TransactionAttributeSource,是由下面transactionAttributeSource方法创建的。这个是@Transactional注解的属性解析类,解析完注解后将属性封装成transactionAttribute对象。在transactionAttributeSource中可以看到它是AnnotationTransactionAttributeSource对象。
        enableTx是@EnableTransactionManagement中的排序属性,是一个map,根据这个属性可以排序切面。
在这里插入图片描述
        事务切面会设置advice,是TransactionInterceptor类型,由下面的transactionInterceptor定义,它继承了MethodInterceptor。
在这里插入图片描述
        在transactionInterceptor中可以看到如果txManager不为空,advice就设置了事务管理器,它是在父类AbstractTransactionManagementConfiguration中定义的。由setConfigurers可以依赖注入TransactionManagementConfigurer,在annotationDrivenTransactionManager方法中返回事务管理器,这就要求定义一个类实现TransactionManagementConfigurer,如下图所示。启动过程中没有txManager无影响,一般也不用这种方式,常用的会在后面说。
在这里插入图片描述
在这里插入图片描述

三、事务切面的Pointcut和Advice

        每个切面都会有Pointcut和Advice。首先看事务切面的PointCut,它定义在BeanFactoryTransactionAttributeSourceAdvisor中,在代理生成之前会调用ClassFilter的matches和MethodMatcher的matches。
在这里插入图片描述
        ClassFilter。TransactionAttributeSourcePointcut第一行就定义了ClassFilter为TransactionAttributeSourceClassFilter,但是这个
ClassFilter其实什么都没做。
在这里插入图片描述
        看到它的matches方法,关键代码是tas.isCandidateClass(clazz)。这里的TransactionAttributeSource为AnnotationTransactionAttributeSource,看到它的isCandidateClass。在这里插入图片描述
        isCandidateClass中循环调用了annotationParsers容器中的TransactionAnnotationParser.isCandidateClass。annotationParsers是在上面AnnotationTransactionAttributeSource中定义的,这里起作用的也就只有
SpringTransactionAnnotationParser。
在这里插入图片描述
        在SpringTransactionAnnotationParser的isCandidateClass中可以看到,它是在找java.开头的注解和java.开头的类。@Transactional注解是Spring定义的,事务相关的类是自定义的,所以都不符合,返回true。于是ClassFilter的matches一直都是返回true。
在这里插入图片描述
        MethodMatcher。TransactionAttributeSourcePointcut继承了StaticMethodMatcherPointcut,StaticMethodMatcherPointcut继承了StaticMethodMatcher,StaticMethodMatcher实现了MethodMatcher,所以TransactionAttributeSourcePointcut本身就是MethodMatcher,它里面定义了MethodMatcher的matches方法。
        matches方法会调用2次, 第一次是找切面的过程,代理对象生成之前会调用一次,第二次是在走拦截器链的时候又会被调用。ClassFilter的matches是一直返回为true的,也就是说只要方法上面能拿到@Transactional注解就生成代理。这里是拿事务属性,拿事务属性就相当于有@Transactional注解。
在这里插入图片描述
        看到AbstractFallbackTransactionAttributeSource的getTransactionAttribute,首先从缓存中取TransactionAttribute,如果不为空直接返回,如果为空,则需要在computeTransactionAttribute中得到TransactionAttribute。
在这里插入图片描述
        computeTransactionAttribute中首先判断方法是否为public,如果是非public方法则返回null不会生成代理。获取原始方法,AopUtils.getMostSpecificMethod(method, targetClass);很有用,它总能拿到原始方法(因为生成代理之后,一般拿到的都是方法的代理)。
在这里插入图片描述
        获取方法上面@Transactional注解的属性,点进去后来到AnnotationTransactionAttributeSource的determineTransactionAttribute,方法中主要是通过SpringTransactionAnnotationParser的parseTransactionAnnotation,拿到@Transactional的属性并封装成TransactionAttribute对象。其中,attributes相当于map,存的都是@Transactional的属性,parseTransactionAnnotation中拿到属性封装成对象。
在这里插入图片描述
        如果方法上没有注解,再通过findTransactionAttribute去类上找注解。点进去可以看到它也是来到AnnotationTransactionAttributeSource的determineTransactionAttribute,逻辑和上面从方法上找注解是一样的。
        再回到AbstractFallbackTransactionAttributeSource的getTransactionAttribute,如果TransactionAttribute不为空,将它放入缓存,然后返回。拿到了事务属性返回true,生成代理。

        Advice。事务切面的Advice即TransactionInterceptor,看到它的invoke方法,invocation::proceed很明显就是一个链式调用。
        进入invokeWithinTransaction。因为ProxyTransactionManagementConfiguration的transactionInterceptor中在依赖注入后将TransactionAttributeSource设置到advice中了,所以能通过getTransactionAttributeSource拿到事务属性类AnnotationTransactionAttributeSource,然后获取事务属性和事务管理器。
在这里插入图片描述
        determineTransactionManager中可以看到如果事务管理器为空,从Spring容器中拿到TransactionManager类型的类作为事务管理器。也就是说,只要自定义一个TransactionManager,注册到Spring容器中,就能引入事务管理器。下面白图中的DataSourceTransactionManager就是TransactionManager,一般都是用这种方式引入事务管理器。
在这里插入图片描述
在这里插入图片描述
        asPlatformTransactionManager是校验事务管理器,methodIdentification是获取方法名称。
在这里插入图片描述

四、注解事务的源码分析

        还是在invokeWithinTransaction方法中。
在这里插入图片描述
        进入createTransactionIfNecessary后,tm.getTransaction(txAttr);主要是开启事务。
在这里插入图片描述
        进入tm.getTransaction(txAttr);再进入doGetTransaction();
DataSourceTransactionObject是事务对象,里面有个newConnectionHolder标识,标识是否是新连接。事务肯定是跟连接对象挂钩的,父类JdbcTransactionObjectSupport中定义了当前连接对象的包装类ConnectionHolder,可以理解为数据库连接对象。JdbcTransactionObjectSupport还定义了连接对象属性相关的信息,包括隔离级别、是否只读、是否允许回滚。所以DataSourceTransactionObject是跟连接对象有关的一些包装。
在这里插入图片描述

        接着看doGetTransaction方法,txObject.setSavepointAllowed(isNestedTransactionAllowed());含义为是否创建回滚点,isNestedTransactionAllowed()默认返回的是true。
        obtainDataSource()是获取数据源对象,即上面例子中设置的数据源,TransactionSynchronizationManager.getResource是根据dataSource从ThreadLocal中获取到连接对象,第一次是没有值的,为null。ThreadLocal的结构是Map<DataSource, ConnectionHolder>
        拿到连接对象后放到事务对象中,设置newConnectionHolder为false。
在这里插入图片描述
        isExistingTransaction(transaction)是判断事务对象中的连接对象是否为空。第一次进来connectionHolder为空,所以if不会走,看到下面的代码。
在这里插入图片描述
        第一次进来会首先判断事务的传播属性,事务的传播属性是用来控制事务流转的。传播属性为REQUIRED、REQUIRES_NEW、NESTED执行下面的代码。传播属性默认为REQUIRED。
        首先将事务挂起,然后执行startTransaction。
在这里插入图片描述
        startTransaction中下面的代码是创建一个新的事务状态。newTransaction为true,这是核心。DefaultTransactionStatus对象主要是标识事务的一些属性,是否是最新事务,是否是旧的事务,Spring可以通过它来控制事务的传播。

DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

        在newTransactionStatus方法中可以看到把事务对象、状态标识、是否挂起等属性都传到了DefaultTransactionStatus中返回。
在这里插入图片描述
        doBegin(transaction, definition);开启事务。首先判断事务对象中有没有连接对象,如果没有连接对象,从dataSource中拿到连接对象,包装成ConnectionHolder后设置到事务对象中,并把newConnectionHolder设置为true。
在这里插入图片描述
        设置有事务标识,设置是否只读连接和事务隔离级别到连接对象中,设置该连接的上一个隔离级别。如果是自动提交,关闭自动提交。
在这里插入图片描述
        把事务活跃状态设置为true,设置事务超时时间。首先判断newConnectionHolder是否为true,现在是为true的。TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());是绑定线程、dataSource、连接对象。在这里可以看到线程对应的是map,map中是数据源对应连接对象。在这里插入图片描述
        从doBegin出来后来到prepareSynchronization,这里是改变TransactionSynchronizationManager中的事务状态。DefaultTransactionStatus是Spring内部流转的事务状态,TransactionSynchronizationManager相当于开发人员使用的事务状态工具类,可以拿到事务的流转状态,是否已经提交、回滚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值