Mybatis管理事务分为三种方式:
mybatis的Transaction接口
- JdbcTransaction:使用JDBC的事务管理机制,利用java.sql.Connection对象完成事务的提交。
- ManagedTransaction:使用Managed的事务管理机制,mybatis自身不会去实现事务管理,而是让容器(JBOSS、WebLogic)实现对事务的管理。
- SpringManagedTransaction:使用spring的事务管理机制,利用@Transaction注解即可实现
有于现在都是基于springboot的项目了,所以就只分析SpringManagedTransaction
先了解一些接口和类
1、TransactionSynchronization接口是Spring的事务扩展接口,是一个回调接口,用于在事务执行过程中的重要时间点执行额外的逻辑,
2、TransactionSynchronizationManager类:使用ThreadLocal管理当前事务的TransactionSynchronization集合
3、ResourceHolderSynchronization类:是用来同步资源的(Spring事务中资源的概念),例如:JDBC中的Connection,Hibernate的Session、JPA的EntiyManager、kafka的Producer。
在mybatis中,SqlSessionUtil类的内部类SqlSessionSynchronization继承了TransactionSynchronizationAdapter适配器类(等于实现了TransactionSynchronization接口)
事务执行过程
一、mybatis事务注册过程
1、从SqlSessionTemplate类创建JDK动态代理类开始,因为无论那种执行sql的方式,最终都会走此代码。
2、直接看SqlSessionInterceptor的invoke方法
可以看到先获取sqlsession,然后通过反射调sqlsession的某个方法,最后满足某种条件才commit提交事务
3、进入getSqlSession方法
从事务同步管理器中拿资源(sqlSessionHolder只把是Sqlsession包装了一层),从sessionHolder中拿sqlsesison。
如果没有sqlsession,则通过sessionFacory创建sqlsession,然后执行registerSessionHolder注册sessionHolder。
4、进入registerSessionHoler方法
先判断Configuration配置类中Evironment环境类中的TransactionFactory事务工厂是不是SpringManagedTransactionFactory或其子类。(springboot环境下,默认是)
包装好SqlSessionHolder,然后向TransactionSynchronizationManager中绑定资源和注册TransactionSynchronization
在springboot中构建SqlSessionFactory时,设置了事务工厂为SpringManagedTransactionFactory。
5、最终把TransactionSynchronization注册到了TransactionSynchronizationManager类的synchronizations静态属性中去了。
二、spring事务动态代理过程
springboot项目,为什么我们使用@Transaction注解到service的方法上就能生效?spring底层是如何实现的?
这就要从@EnableTransactionManagement注解开始说起
1、springboot项目的autoconfig包中已经注解了EnableTransactionManagement
2、EnableTransactionManagement注解Import了TransactionManagementConfigurationSelector类,在spring容器初始化是会把此类加载到容器。
3、由于TransactionManagementConfigurationSelector类实现了ImportSelector接口,所以spring容器把返回值的这两个类加入容器
ProxyTransactionManagementConfiguration类主要用于注册和配置BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor这三个类
4、继续看AutoProxyRegistrar类,它实现了ImportBeanDefinitionRegistrar接口
所以它会执行registerBeanDefinitions方法,用于注册BeanDefinition。
5、其中有个方法registerAutoProxyCreatorIfNecessary,用于注册InfrastructureAdvisorAutoProxyCreator类
只不过它的注册Bean的方式使用了直接new RootBeanDefinition的方式,也是向spring容器注入InfrastructureAdvisorAutoProxyCreator类
6、InfrastructureAdvisorAutoProxyCreator类又实现了BeanPostProcessor接口
用于在bean的初始化的前后对bean做处理,所以会执行postProcessBeforeInitialization方法,用于在bean实例化之前做处理
aop代理肯定是在原bean初始化之后去做,在原bean的基础上增加一次代理包装。
7、wrapIfNecessary方法,如果有必要则创建Proxy代理
8、createProxy方法用于创建动态代理,并返回
三、spring(mybatis)事务执行过程
1、TransactionInterceptor为事务方法拦截执行器,实现了MethodInterceptor接口
2、当调用注解@Transaction的方法时,会执行TransactionInterceptor的invoke方法,因为该方法的类已经被aop代理了。
3、进入invokeWithTransaction方法
TransactionAttribute:为事务相关信息。如注解型事务,看方法获取类上有没有注解@Transactional
PlatformTransactionManager:为
事务管理器
TransactionInfo:为事务信息。里面包含事务管理器和事务相关信息
proceedWithInvocation:为调用真正被代理对象service的方法
4、调用真正被代理对象service的方法之后,要进行commitTransactionAfterReturning提交事务
5、进入到事务管理器类的commit方法
6、进入processCommit方法
triggerBeforeCommit:用于触发TransactionSynchronization类的beforeCommit方法
triggerBeforeCompletion:用于触发TransactionSynchronization类的beforeCompletion方法
doCommit:用于spring事务的提交
7、进入TransactionSynchronizationUtils方法进行回调一开始保存在synchronizations属性中的TransactionSynchronization实现类
比如mybaits一开始定义的SqlSessionSynchronization类
8、进入mybatis的SqlSessionSynchronization类的beforeCommit方法
从sqlSessionHolder中取出sqlSesion,执行commit方法提交事务
完毕