Spring 事务处理机制详解及源码分析
事务做了那些事儿
今天这里记录下spring的事务机制,大概分析下spring是如何处理事务的,spring中有很多事务的传播特性,但是这和数据库没有关系,是由spring本身去实现的一些机制;说到事务,我们从数据库方面来看,不就是开始事务、执行业务逻辑、提交事务或者回滚事务吗,事务我们一般可以把它叫做就是一个数据库的连接。一个数据库连接可以代表为一个事务,我们一般使用应用程序去执行一条sql数据的时候,这个时候应用程需要和数据库建立连接,然后执行sql,最后关闭连接,但是不是就没有事务存在了吗?其实不是,就以mysql数据库来说,它的事务是默认打开比较默认提交的,也就是你在执行sql语句完成过后,由mysql本身给你提交事务了,不需要手动的去提交一个事物,当sql执行完成过后,会提交事务,并且关闭事务连接;
spring的事务处理过程,简单来说就是设置数据库的自动提交为false,然后由spring来控制事务的提交,事务该什么时候提交,什么时候回滚,我们先来看一个例子,我使用mybatis来向mysql插入一条数据:
首先我们先看数据库现在的连接数:
使用mysql本身的事务来控制:
看上面的断点,这个就没有spring的事务去控制的,并且连接也是mybatis自己去建立的连接,而不是spring给我们建立的连接,这个时候我们看数据库的连接数没有变,还是3,因为已经建立了连接并且释放了连接
而其实我们的代码还在这个方法里面,所以像这种就是数据自身来控制的事务,那么如果我们的test方法里面其实有很多数据库的连接操作,如果说不用一种事务机制来控制事务,那么出现的结果就是这个test方法不是一个原子性的操作,数据库方面的事务隔离级别下来有兴趣的去研究研究,我这里只说spring的事务机制;然后我们如果加入了spirng的事务的话,那么这个时候的mysql数据库的连接就不是mybatis给我们建立的连接了,而是spring给我们建立的连接,并且加入了事物的管理,看下面的例子:
这个时候我们的test方法加入了事物,断点到这里的时候,我们看下数据库的连接数:
连接数为5,所以这个时候test方法还没有完成,所以事务没有提交,test方法加入事务处理过后,是一个整体,在这个方法没有执行完成,事务是不会提交的。
当我们的一个完整的整体加入事务过后,在这个整体的操作中都不会提交事务的,只有当操作完成过后提交或者操作过程中出现异常才会回滚;其实spring底层源码中对事物的处理也是获取连接过后设置连接的自动提交设置为false,然后等操作完成过后,一次性提交所有的操作,简单来说就是这样做的,但是spring还提供了很多的事物处理方式,比如说在当前已有的事务中出现了一个新的事务是怎么处理的,下面我们就来分析下spring的几种事务机制。
spring事务传播特性
spring的事务传播特性有好几种,比如说一个test操作是一个事物操作整体,如果在这个test过程中没有出现新的事务,简单来说就是当前事物不存在其他事物,那么从源码分析来看有这几种特性:
当前不存在新的事务
MANDATORY:spring目前不支持,直接抛出异常
REQUIRED:新建一个事物
REQUIRES_NEW:新建一个事物
NESTED:新建一个事物
其他情况:以非事务的方式运行
当前存在一个新的事务(事务需要传播)
NEVER:直接抛异常
NOT_SUPPORT:挂起当前事物,以非事物方式运行,运行完毕,唤醒挂起的事务
REQUIRES_NEW:挂起当前事务,新建一个事物运行,新事务完成过后,提交新事务,唤醒挂起事务,让之前事务继续运行;
NESTED:在当前事物开始时,新建一个保存点,然后执行,如果执行完全成功,全部提交,如果出现回滚,那么回滚到保存点,原先的事务正常执行提交或者回滚;
其他情况 :在当前的事务中运行。
上面的“当前不存在新的事务”和“当前存在一个新的事务”的意思就是说比如我们在执行一个test是由事务的方法时,但是在test方法中又调用了另外一个有事物的方法,这个时候spring就有相对应的传播机制来处理事务;
如果说test方法中没有出现新的事务,那么就直接在当前的事务中运行完毕。
举个例子
事务传播特性为REQUIRES_NEW:
比如说我们的一个test方法是一个完整的事务,但是在test方法中调用了另外一个也有事物的方法,这个新的事务的传播属性为REQUIRES_NEW,那么spring在整个过程中是如何处理的,比如:
@Component
public class InfoService {
@Autowired
private InfoMapper infoMapper;
@Autowired
private InfoService infoService;
@Transactional(propagation = Propagation.REQUIRED)
public void test(){
infoMapper.insertInfo(new Info("bml", 34));
infoService.t2();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void t2(){
infoMapper.insertInfo2(new Info("zs", 32));
}
}
上面的test的传播属性是REQUIRED,而t2是REQUIRES_NEW,上面我们说了传播属性是REQUIRES_NEW的情况下,t2会重新新建一个事务,挂起test事务,当t2执行完成过后,会提交或者回滚t2的事务,然后唤醒test的事务,让test的事务继续运行,但是如果说t2在执行的过程中出现异常,那么这个时候到底test事务会不会提交,那么这个就要看你的t2有没有抓到这个异常,如果t2抓到这个异常了,没有抛出去,那么只会回滚t2的事务,如果你没有抓这个异常或者你抓到了抛出去了,那么这两个事务都会被回滚。
我们就以test和t2这两个事务的传播来举个例子分析下事务传播属性为REQUIRES_NEW的时候spring是如何处理的:
test的事务:
test事务开始,获取一个连接,设置连接属性为true(表示新的连接)
设置test事务的自动提交模式为false
初始化事务管理器的其他参数(ThreadLocal中属性)
将获取的连接放入当前线程的缓存对象resource(ThreadLocal)中
执行test的业务逻辑,执行infoMapper.insertInfo(new Info(“bml”, 34));数据库插入
执行 infoService.t2();发现t2是一个新的事务,并且传播属性为REQUIRES_NEW
t2的事务:
- 这个时候t2挂起test事务,挂起事务就是将事务管理器中的所有事务属性和其他属性取出来放入到一个对象中,这个对象就是事务挂起对象,封装了事物管理器中的所有属性,清空事务管理器对象;
2.t2新建一个事物,也就是新建一个连接,放入当前缓存的事务管理器中;
3.t2开始执行业务逻辑,t2执行infoMapper.insertInfo2(new Info(“zs”, 32));
4.t2执行完成过后提交t2的事务,提交事务完成过后发现当前事物有挂起的事务,然后清空事务管理器中的事务信息,将之前挂起的事务恢复到事务管理器中,让test的事务进行执行。
如果说事务的传播属性为NOT_SUPPORT,那么和上面的流程差不多,唯一不一样的就是说t2的操作是以非事务的方式运行的,等t2完成过后也要唤醒被挂起的事务。
源码分析
事务同步管理器
TransactionSynchronizationManager是spring的事务同步管理器,这个事物同步管理器保存了当前事物的所有信息,我们一直所说的事务传播都是在一个线程内运行的,在一个线程内运行的业务逻辑都是顺序执行的,如果两个事务都在不同的线程中运行,那么就不存在事务的传播,所以事务同步管理器中主要以本地线程缓存的方式来存储的,就是出现事物的传播在一个线程内完成的。
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
//存放了 事务连接对象,是一个Map,其中key是dataSouce,而value是事物的连接对象
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
//存放开发者注册的事务注册事件
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
//存放当前事物执行的名字
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
//存放当前事物是否是只读属性的
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
//存放当前事物的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
//存放当前事物是否是激活的
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
......
上面的事务同步管理器中有一个可能大家很少用过或者根本就没有用过,就是synchronizations,这个synchronizations存放的就是开发者注册一些事件,我这里理解为事件,其实和spring的bean后置处理器中的初始化前后,实例化前后的意思一样,我这里说的事件是说在事物的某一个阶段中执行的一些回调,不算是spring的事件机制,只是我理解为一个事件;我们来看下这个同步事件的结构
public interface TransactionSynchronization extends Flushable {
/** Completion status in case of proper commit. */
int STATUS_COMMITTED = 0;
/** Completion status in case of proper rollback. */
int STATUS_ROLLED_BACK = 1;
/** Completion status in case of heuristic mixed completion or system errors. */
int STATUS_UNKNOWN = 2;
/**
* 当事务挂起的时候触发的事件
* Suspend this synchronization.
* Supposed to unbind resources from TransactionSynchronizationManager if managing any.
* @see TransactionSynchronizationManager#unbindResource
*/
default void suspend() {
}
/**
* 当事务恢复的时候触发的事件
* Resume this synchronization.
* Supposed to rebind resources to TransactionSynchronizationManager if managing any.
* @see TransactionSynchronizationManager#bindResource
*/
default void resume() {
}
/**
*
* Flush the underlying session to the datastore, if applicable:
* for example, a Hibernate/JPA session.
* @see org.springframework.transaction.TransactionStatus#flush()
*/
@Override
default void flush() {
}
/**
* Invoked before transaction commit (before "beforeCompletion").
* Can e.g. flush transactional O/R Mapping sessions to the database.
* <p>This callback does <i>not</i> mean that the transaction will actually be committed.
* A rollback decision can still occur after this method has been called. This callback
* is rather meant to perform work that's only relevant if a commit still has a chance
* to happen, such as flushing SQL statements to the database.
* <p>Note that exceptions will get propagated to the commit caller and cause a
* rollback of the transaction.
* @param readOnly whether the transaction is defined as read-only transaction
* @throws RuntimeException in case of errors; will be <b>propagated to the caller</b>
* (note: do not throw TransactionException subclasses here!)
* @see #beforeCompletion
* 当事务提交之前执行的事件
*/
default void beforeCommit(boolean readOnly) {
}
/**
* Invoked before transaction commit/rollback.
* Can perform resource cleanup <i>before</i> transaction completion.
* <p>This method will be invoked after {@code beforeCommit}, even when
* {@code beforeCommit} threw an exception. This callback allows for
* closing resources before transaction completion, for any outcome.
* @throws RuntimeException in case of errors; will be <b>logged but not propagated</b>
* (note: do not throw TransactionException subclasses here!)
* @see #beforeCommit
* @see #afterCompletion
* 当事务完成之后执行的事件
*/
default void beforeCompletion() {
}
/**
* Invoked after transaction commit. Can perform further operations right
* <i>after</i> the main transaction has <i>successfully</i> committed.
* <p>Can e.g. commit further operations that are supposed to follow on a successful
* commit of the main transaction, like confirmation messages or emails.
* <p><b>NOTE:</b> The transaction will have been committed already, but the
* transactional resources might still be active and accessible. As a consequence,
* any data access code triggered at this point will still "participate" in the
* original transaction, allowing to perform some cleanup (with no commit following
* anymore!), unless it explicitly declares that it needs to run in a separate
* transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW} for any
* transactional operation that is called from here.</b>
* @throws RuntimeException in case of errors; will be <b>propagated to the caller</b>
* (note: do not throw TransactionException subclasses here!)
* 当事务提交之后执行的事件
*/
default void afterCommit() {
}
/**
* Invoked after transaction commit/rollback.
* Can perform resource cleanup <i>after</i> transaction completion.
* <p><b>NOTE:</b> The transaction will have been committed or rolled back already,
* but the transactional resources might still be active and accessible. As a
* consequence, any data access code triggered at this point will still "participate"
* in the original transaction, allowing to perform some cleanup (with no commit
* following anymore!), unless it explicitly declares that it needs to run in a
* separate transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW}
* for any transactional operation that is called from here.</b>
* @param status completion status according to the {@code STATUS_*} constants
* @throws RuntimeException in case of errors; will be <b>logged but not propagated</b>
* (note: do not throw TransactionException subclasses here!)
* @see #STATUS_COMMITTED
* @see #STATUS_ROLLED_BACK
* @see #STATUS_UNKNOWN
* @see #beforeCompletion
* 当事务完成之后的事件
*/
default void afterCompletion(int status) {
}
}
总结一下就是:
当事务恢复的时候, 执行resume
当挂起一个事物的时候,执行挂起的事件suspend
当回滚一个事物的时候:
执行beforeCompletion
执行回滚
执行afterCompletion
当提交一个事物的时候:
执行beforeCommit
执行beforeCompletion
执行提交事务
执行afterCommit
执行afterCompletion
事务挂起注册
@Transactional(propagation = Propagation.REQUIRED)
public void test(){
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
@Override
public void suspend() {
System.out.println("事务挂起了....");
}
@Override
public void resume() {
System.out.println("事务恢复了....");
}
});
infoMapper.insertInfo(new Info("bml", 34));
infoService.t2();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void t2(){
infoMapper.insertInfo(new Info("zs", 32));
}
我们在t2打一个断点,那么这个时候应该是t2开启了一个新的事务,test的事务被挂起,那么就要执行我们的事务挂起了事件suspend
事务挂起的事件被打印了,我们执行完t2,应该事务恢复了也会打印
事务回滚时的事件
@Transactional(propagation = Propagation.REQUIRED)
public void test(){
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
@Override
public void suspend() {
System.out.println("事务挂起了....");
}
@Override
public void resume() {
System.out.println("事务恢复了....");
}
@Override
public void beforeCompletion() {
System.out.println("事务完成之后的事件。。。。");
}
@Override
public void afterCompletion(int status) {
System.out.println("事务完成之前的事件。。。。");
}
});
int n = 100/0;
//infoMapper.insertInfo(new Info("bml", 34));
//infoService.t2();
}
我们让程序执行100/0报错回滚事件
事务提交事件
@Transactional(propagation = Propagation.REQUIRED)
public void test(){
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
@Override
public void suspend() {
System.out.println("事务挂起了....");
}
@Override
public void resume() {
System.out.println("事务恢复了....");
}
@Override
public void beforeCompletion() {
System.out.println("事务完成之后的事件。。。。");
}
@Override
public void afterCompletion(int status) {
System.out.println("事务完成之前的事件。。。。");
}
@Override
public void beforeCommit(boolean readOnly) {
System.out.println("事务提交之前的事件。。。。");
}
@Override
public void afterCommit() {
System.out.println("事务提交之后的事件。。。。");
}
});
//infoMapper.insertInfo(new Info("bml", 34));
//infoService.t2();
}
@EnableTransactionManagement
spring中的事务管理器借助了spring的AOP来实现的,就是上一篇笔记中记录了AOP的生成过程,而spring的事务也是通过aop来实现的,如果说你的bean加了@Transactional或者方法上面加了@Transactional注解,那么就代表你要生成一个aop代理对象,而这个aop的代理对象的代理逻辑也就是advisor也是spring注册进去的,我们要清楚明白的是事物管理就是两部分东西,第一部分就是产生aop代理对象,第二部分就是代理对象具体要执行的逻辑,也就是代理对象要执行原始对象的时候通过代理的拦截器拦截到然后产生事务从而产生事务的一系列操作。我们要在系统中开启一个事物,必须要加@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* spring的事物管理的注解类,它也是使用spring自己提供的@Import方式导入了事物处理的相关类信息
* 看下面的@Import就知道导入的是一个selector,而selector类型的bean,spring会回调selectImports方法,然后将返回的
* 类信息列表作为一个BeanDefinition进行注册
* 在TransactionManagementConfigurationSelector中导入了两个BeanDefinition,
* 1.AutoProxyRegistrar aop的代理bean后置处理器的BeanDefinition;
* 2.ProxyTransactionManagementConfiguration事物管理的一个配置类,
* 主要处理向sprinng容器通过@Bean注册advisor类,注册advisor的时候是通过加了@Transactional注解的方法或者类生成一个advisor
* 然后第一步去做aop代理的时候就会扫描到业务类中加了@Transactional注解的类然后创建aop代理,其中我们都知道aop代理的advisor需要
* 两个条件:就是切点和代码逻辑,即pointcut和advice
* 所以第一步是aop去找到第二步向容器添加的advisor bean,而如果一个bean加了@Transactional,那么在找到的所有的advisor的时候
* 会去判断是否加了@Transactional,如果加了就会是一个advisor,作为代理对象的一个切入点
*/
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
.....
从上面可以知道spring又是利用了spring的@Import的扩展来实现的事务的处理,两部分:产生AOP代理对象和生成对应的代理逻辑advisor;spring这里使用的是@Import的selector,我们看下具体的源码:
TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//这边会导入两个BeanDefinition
/**TransactionSynchronizationManager
* 1.AutoProxyRegistrar AOP代理,为每个符合的bean创建一个代理对象(方法加了@Transactional或者bean上加了@Transactional)
* 2.ProxyTransactionManagementConfiguration就是导入一些Advisor的切面类作为一个BeanDefinition;
* 也就是像前面说的aop,不管是开发者自定义的还是使用@Aspject,那么最终都会有一个advisor切面类,所以第2步就是
* 创建这些切面类,说白了就是切点和通知逻辑,然后第一步在创建aop的时候回去根据当前bean看是否满足第2步创建
* 的advisor的切点条件,如果满足,那么就会为当前创建的bean创建一个aop代理对象,
* 所以我们要关心的就是通知的具体业务逻辑,看spring是如何工作的
*/
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
spring在启动过程中会扫描到@Import,并且会调用selectImports方法得到一个数组列表,列表里面有两个类AutoProxyRegistrar和ProxyTransactionManagementConfiguration,这两个类第一个一看就知道是产生AOP代理对象的,而产生AOP代理对象的依据是什么呢?就是AutoProxyRegistrar在导入bean的时候会注册一个bean,这个bean也是bean的后置处理器,我们知道aop都是通过bean的后置处理器来完成的,所以事务的代理对象产生也是通过bean的后置处理器来产生aop代理对象的,但是AutoProxyRegistrar种导入的bean是InfrastructureAdvisorAutoProxyCreator,而这个类重写了一个方法:
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
isEligibleAdvisorBean就是在spring创建bean的过程中先找到所有的advisor,事务的advisor就是下面的ProxyTransactionManagementConfiguration 通过@Bean导入的BeanFactoryTransactionAttributeSourceAdvisor,那么找到过后就要判断这个bean(advisor bean)role是否是BeanDefinition.ROLE_INFRASTRUCTURE,但是我们看导入的bean advisor呢
这里就是注册的advisor成为一个BeanDefinition,而我们看下注册方法呢
所以说重写的isEligibleAdvisorBean就是简单的判断role是否是ROLE_INFRASTRUCTURE,所以aop的代理对象肯定是能创建出来的,只要你加了@EnableTransactionManagement
而ProxyTransactionManagementConfiguration是什么呢?这个就是说一个代理逻辑的配置类,我们看下:
/**
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @author Sebastien Deleuze
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*
* 这个类就非常重要了,是spring的事物管理的配置类
* 这里面回注册一个非常重要的advisor BeanFactoryTransactionAttributeSourceAdvisor
* 这个advisor会传入两个参数 即pointcut和advice
* 然后spring在创建代理对象的时候会找到这个advisor,然后根据
* 当前创建的bean是否满足pointcut,从而决定是否要创建aop代理对象
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
/**
* 这个创建的bean接受两个参数
* AnnotationTransactionAttributeSource类型的主要处理验证,比如验证一个是否加了@Transactional注解的
* 而TransactionInterceptor是一个拦截器,也就是具体的advice,生成的代理对象调用原始对象中的方法
*都会被它所拦截,然后它来处理处理事务相关的业务逻辑
* BeanFactoryTransactionAttributeSourceAdvisor这个advisor的切点是什么呢?是不是都很好奇,因为aop中的切点还是
* 很重要的,每个bean要根据切点是否满足才能拦截到从而执行对应的advice
* BeanFactoryTransactionAttributeSourceAdvisor中的切点
*/
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
//添加一个拦截器,
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
上面的代理逻辑导入了两个bean,一个是TransactionAttributeSource ,一个是TransactionInterceptor ,TransactionInterceptor 是代理的逻辑拦截器,而TransactionAttributeSource 主要是用来判断我们的bean是否是一个事物的判断和获取如果是一个事物的方法过后得到@Transactional注解的信息
public interface TransactionAttributeSource {
/**
* Determine whether the given class is a candidate for transaction attributes
* in the metadata format of this {@code TransactionAttributeSource}.
* <p>If this method returns {@code false}, the methods on the given class
* will not get traversed for {@link #getTransactionAttribute} introspection.
* Returning {@code false} is therefore an optimization for non-affected
* classes, whereas {@code true} simply means that the class needs to get
* fully introspected for each method on the given class individually.
* @param targetClass the class to introspect
* @return {@code false} if the class is known to have no transaction
* attributes at class or method level; {@code true} otherwise. The default
* implementation returns {@code true}, leading to regular introspection.
* @since 5.2
判断是否是一个事物的验证也就是是否加了@Transactional注解
*/
default boolean isCandidateClass(Class<?> targetClass) {
return true;
}
/**
* Return the transaction attribute for the given method,
* or {@code null} if the method is non-transactional.
* @param method the method to introspect
* @param targetClass the target class (may be {@code null},
* in which case the declaring class of the method must be used)
*获取事物的属性
@return the matching transaction attribute, or {@code null} if none found
*/
@Nullable
TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
}
事物核心拦截器
当我们的一个bean被创建为一个事物的代理对象的时候,当代理对象调用原始对象的方法时,会进入代理逻辑的拦截器中进行处理
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
/**
* Create a new TransactionInterceptor.
* <p>Transaction manager and transaction attributes still need to be set.
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @see #setTransactionAttributeSource(TransactionAttributeSource)
*/
public TransactionInterceptor() {
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @since 5.2.5
* @see #setTransactionManager
* @see #setTransactionAttributeSource
*/
public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @see #setTransactionManager
* @see #setTransactionAttributeSource
* @deprecated as of 5.2.5, in favor of
* {@link #TransactionInterceptor(TransactionManager, TransactionAttributeSource)}
*/
@Deprecated
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param attributes the transaction attributes in properties format
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @deprecated as of 5.2.5, in favor of {@link #setTransactionAttributes(Properties)}
*/
@Deprecated
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
setTransactionManager(ptm);
setTransactionAttributes(attributes);
}
/**
* 真正的业务事务开始的地方,简单理解就是如果你的bean上面加了@Transactional注解或者方法上的话
* 那么spring就会生成aop代理对象,当代理对象调用原始对象的方法时候,就会到这个拦截器的方法中
* @param invocation the method invocation joinpoint
* @return
* @throws Throwable
*/
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
//得到目标的class
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
//真正的调用开始的地方
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
真正的核心是invokeWithinTransaction
invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
//这里得到的TransactionAttributeSource 就是在代理配置类 通过这个代码advisor.setTransactionAttributeSource(transactionAttributeSource);
TransactionAttributeSource tas = getTransactionAttributeSource();
//添加进来的,具体的思路如下:
/**
* 首先这里的TransactionAttributeSource在添加到本对象的时候是在ProxyTransactionManagementConfiguration这个配置类中通过
* @Bean添加的BeanFactoryTransactionAttributeSourceAdvisor一个Advisor,这Advisor又设置了一个transactionAttributeSource
* 而这个transactionAttributeSource是从容器中拿到的,是一个AnnotationTransactionAttributeSource
* 然后TransactionAttributeSource又是AnnotationTransactionAttributeSource的子类,而AnnotationTransactionAttributeSource
* 的父类AbstractFallbackTransactionAttributeSource,所以下面的代码getTransactionAttribute真正的调用地方是
* AbstractFallbackTransactionAttributeSource中的getTransactionAttribute方法,结构理清楚了,那么我们来分析下在调用
* getTransactionAttribute这个方法到底做了什么事儿?
* 这里方法里面比较深,其实简单来说就是根据当前方法method去找是否有@Transaction注解,如果找到了,就封装成一个
* TransactionAttribute对象返回
*/
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//获取一个事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
//下面的这个if没有具体细看,但是一般我们的业务事务不会到if里面
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
/**
* asPlatformTransactionManager方法就是判断从容器中获取的TransactionManager是否是
* PlatformTransactionManager类型,如果是PlatformTransactionManager类型就强制转换
* 成PlatformTransactionManager返回,否则就报错
*/
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
//这里得到的是拦截的方法的全限定名(类的全限定名+方法名字,如com.xxx.Test.test
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//事务开始的地方
/**
* 这里简单说明下,createTransactionIfNecessary方法就是开启事物,spring根据事物的传播机制
* 进行不同的处理,我这边简单列举下几个常用的特性
* REQUIRED:整个事物中都是一个事物进行处理的,传播的特性是REQUIRED,那么共用一个事物,不会开启其他的事物
* 处理完毕过后一起提交,就是所有的业务逻辑,包括在整个事物中调用了其他开启了事物的方法都是共用一个事物
* 一次性提交,一次性回滚,传播特性决定了所有的业务处理都在一个事务中完成,我这里说的是所有的传播特性都是REQUIRED
* REQUIRED_NEW:当传播特性是REQUIRED_NEW的情况下, 在同一个线程中的时候,那么先挂起当前事物,开启一个新的事物
* 当当前事物处理完成过后,提交REQUIRED_NEW的事物,唤醒开启事物前的事物,继续执行原先的事物
* NESTED:会在当前执行的事物中新增一个保存点,当前事物发现异常,会回滚到保存点的地方,在当前事物的前面的事务不回滚
* 如果都执行没有出现异常,那么不会单独提交保存点的事务,而是一起提交
* NEVER:如果在一个线程中,存在了一个已有的事务,而下一个事务是NEVER,那么抛异常
* NOT_SUPPORT:抛弃spring的事务管理,不启用事务,使用数据库默认的自动提交机制,也就是这里使用的
* 不是spring创建的连接了,而是使用mybatis创建的连接
* 其他的默认就是REQUIRED,直接在当前事物中运行
*
* 当出现事物的传播机制过后,那么传播机制有作用的前提条件是所有的事物都在一个线程中执行的,比如说
*在方法为test,传播机制为REQUIRED,那么在test中调用一个test2方法, 而test2方法的传播机制为REQUIRED_NEW
* 如果在一个线程中,执行到test2的时候会将test的事务进行挂起,test2新建一个事务,当test2执行完成过后提交了当前
* 事务,在唤起test的事务继续执行,test执行完成过后进行提交;这些都是在一个线程中执行的,如果在test方法中
* 调用test2的时候是重新开启了一个线程,那么上面的说法就不起作用,而是一个新的事务,不会挂起test的事务
* 就等于两个不相干的事务在运行而已
*
* 为什么这样说呢?因为spring的底层源码每当一个事物开始的时候,就使用的ThreadLocal存储了的事务的信息
* 所以如果不在一个线程内就不起作用
*
*/
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//调用业务逻辑,就是方法里面的代理逻辑的调用,比如sql,但是里面又可能又会开启一个新的事务
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//出现异常回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除线程本地的缓存
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
Object result;
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
getTransactionAttribute
获取事物属性
/**
* Determine the transaction attribute for this method invocation.
* <p>Defaults to the class's transaction attribute if no method attribute is found.
* @param method the method for the current invocation (never {@code null})
* @param targetClass the target class for this invocation (may be {@code null})
* @return a TransactionAttribute for this method, or {@code null} if the method
* is not transactional
* 获取当前调用的方法的@Transactional的信息
*/
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
//先从缓存中取
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.
//这里就是去找到@Transaction的注解信息,然后封装成一个TransactionAttribute对象,然后返回
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
//如果为空,则放入一个空的对象
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
/**
* Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
* <p>As of 4.1.8, this method can be overridden.
* @since 4.1.8
* @see #getTransactionAttribute
* 这个方法就是来判断当前调用的方法是否是一个@Transactional的事物方法
*/
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
//首先判断是否只允许public的方法,如果是非public的方法,直接返回null,不支持
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
//找到@Transactional的注解信息返回到txAttr
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
findTransactionAttribute.determineTransactionAttribute
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
//这里就是去找到@Transactional注解信息,然后封装成一个完整的对象TransactionAttribute返回
//这里使用的是一个解析器SpringTransactionAnnotationParser
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
//获取@Transactional的注解信息
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
//然后封装成一个TransactionAttribute
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
determineTransactionManager
@Nullable
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
//这里是通过Qualifier去找TransactionManager
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
//这里先获取一个TransactionManager,但是如果你没有设置TransactionManager的话,那么获取到的肯定是空的
//如果是空的,那么spring就回去容器中获取一个,这个是需要开发者在配置类中通过@Bean的方式导入一个
//导入的类型必须是PlatformTransactionManager,这个是spring定的,后面会有判断
//最后返回获取到的PlatformTransactionManager
TransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
createTransactionIfNecessary
/**
* Create a transaction if necessary based on the given TransactionAttribute.
* <p>Allows callers to perform custom TransactionAttribute lookups through
* the TransactionAttributeSource.
* @param txAttr the TransactionAttribute (may be {@code null})
* @param joinpointIdentification the fully qualified method name
* (used for monitoring and logging purposes)
* @return a TransactionInfo object, whether or not a transaction was created.
* The {@code hasTransaction()} method on TransactionInfo can be used to
* tell if there was a transaction created.
* @see #getTransactionAttributeSource()
* 创建一个事物,如果可以的话,也就是满足条件的情况下
* txAttr:是加了@Transactional注解的方法的注解信息,包括了事物传播机制属性信息
*/
@SuppressWarnings("serial")
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
//如果说加了@Transacational的方法的属性信息不为空
if (txAttr != null) {
if (tm != null) {
//获取一个事物状态
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
//将返回的事务状态对象封装成一个事物信息对象TransactionInfo返回
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
getTransaction
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
* 获取一个事物状态
*/
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
/**
* 这里是去获取一个事务(一个连接,从当前线程缓存中获取)每次都会创建一个新的对象
* DataSourceTransactionObject
*/
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
/**
* 这里是判断获取的连接对象是否是一个有效的连接的对象,如果
* 这里返回true,证明在当前线程中出现了其他事物,就是出现了事物的传播
* 也就是说在一个test的事务方法中执行了调用了其他的方法,其他的方法也出现了事物,
* 如果是是一个非事物的方法调用了一个事物方法,那么获取的事务肯定不是活跃的,也就是连接是空的
* 但是如果在一个已有的事务中调用了其他的方法,其他方法也是一个事物,那么这里就会返回true
*
*/
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
//出现了事物传播,也就是在一个事物的方法中调用了另外一个事物
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
//设置连接的超时时间,超过超时时间,数据库自动断开连接
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
//事物不能是PROPAGATION_MANDATORY,没有这种事物机制,也就是说spring目前不支持MANDATORY这种机制
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
/**
* 代码执行到这里的意思就是说,这里是事物第一个调用的地方,比如说我们的一个事物方法test,
* 外部非事物的方法调用这个事物test方法,那么这个时候没有出现事物传播就会进入这里
* 前面大概介绍了事物的传播的几个特性,因为这里是事物的第一个调用,所以还没出现传播
* 所以REQUIRED、所以REQUIRED_NEW 、NESTED都是一样的处理,只有当出现了事物的传播
* 才会有不一样的地方,大概总结就是:
* 传播特性为REQUIRED,那么所有的业务操作都会在一个事物中进行
* 传播特性为REQUIRED_NEW,挂起当前事物,开启一个新的事务,新的事务完成提交,恢复之前的事务
* 传播特性为NESTED,也只有一个事物,但是会设置一个保存点
*/
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
//初始化事务的一些其他信息,主要是线程缓存的一些事务信息,这里调用传入的null,就是初始化
//不是事物挂起
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
//开始一个新的事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
//这里就是没有用事务了,如果一个方法是事物的方法,但是传播特性不是上面的几种,那么就等于没有用@Transacational
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
/**
* Create a TransactionStatus for an existing transaction.
* 这个是出现了当前传事物的时候调用的,就是在同一个线程中,在一个具有事物的方法中去调用了另外一个有事物的方法
* 所以就会走这里,所以如果说进入这里那么一般都是调用了两次拦截器的invoke方法
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
/**
* 如果出现了事物的传播,而传播的子事物是NEVER,直接报错
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
/**
* 当事务的传播特性是NOT_SUPPORT的时候,之前的事务被挂起,当前事物设置为null,这个时候
* 事物就是使用的mybatis的事务了,也就是数据库自身的事务,数据库自身都是autoCommit=true的
* 所以如果传播特性是NOT_SUPPORT,那么就挂起当前事物
* spring退出,由数据库自己去控制,执行完成过后,唤醒spring之前的事务
* 继续之前
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
//将先前的事务挂起,清空resources
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
//返回一个非事物的事务状态对象
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
/**
* 当事务传播特性是REQUIRES_NEW时,挂起当前事物,新开一个事物
* 新开事物执行完成提交,再唤醒之前的事务,让之前的事务继续执行
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
//挂起当前事物
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
//新开一个事物
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
//出现异常,恢复之前的事物,suspendedResources就是之前挂起事务的事务对象信息
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
/**
* 当事务的传播特性是NESTED,在当前的事务添加一个保存点
* 添加保存点的作用是如果出现异常,可以回滚到保存点的地方,但是提交是一起提交的
* 也就是说不能提交到一个保存点
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
//在事物状态中添加一个保存点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
//其他情况以非事物的方式运行
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
/**
* Create a new TransactionStatus for the given arguments,
* also initializing transaction synchronization as appropriate.
* @see #newTransactionStatus
* @see #prepareTransactionStatus
* 封装一个新的事务状态对象,如果是新建的事务,那么初始化除了事物连接信息以外的其他信息
*/
protected final DefaultTransactionStatus prepareTransactionStatus(
TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
prepareSynchronization(status, definition);
return status;
}
/**
* Suspend the given transaction. Suspends transaction synchronization first,
* then delegates to the {@code doSuspend} template method.
* @param transaction the current transaction object
* (or {@code null} to just suspend active synchronizations, if any)
* @return an object that holds suspended resources
* (or {@code null} if neither transaction nor synchronization active)
* @see #doSuspend
* @see #resume
* 这个方法是事物挂起的方法,spring中对于有两种情况需要对事务进行挂起,
* 第一种情况:当在一个事物中开启了一个新的事务,而这个新开的事务是REQUIRED_NEW,那么就需要挂起当前事物
* 然后开启一个新的事务;
* 第二种情况:就是当前事物中出现了另外一个事物,而另外的一个事物是NOT_SUPPORT,那么NOT_SUPPORT已经脱离了spring
* 的事务管理,是由mybatis自己管理的事务,也就是数据库自己管理的事务,所以这个时候也需要把之前的事务挂起
*
* 事务挂起:
* 事务的挂起不要想的太复杂,事物的处理要清楚的概念是;
* 1.事务都是使用的TransactionSynchronizationManager来操作的;
* 2.事务的获取和创建都是会放入到了TransactionSynchronizationManager的resource(ThreadLocal)中
* 所以事务都是同一个线程中的,如果是不同的线程,那么事物间是没有关系的,也就是不属于传播了。
*
* 说了事物的操作就是在Threadlocl中存入了连接的信息,所以事务的挂起就很简单了:
* 1.将当前事物的所有本地线程缓存的信息(事物、其他信息)取出来放入SuspendedResourcesHolder对象中;
* 2.然后清除Threadlocl中的事务信息和其他信息;
* 3.然后将从Threadlocl中取出的事务信息返回;
* 4.清空了Threadlocl中的事务信息过后,创建一个新的事务放入Threadlocl中作为当前新传播事物的信息;
* 5.等当前事务执行完成过后,清除Threadlocl中的事务信息,再把之前的事务从SuspendedResourcesHolder对象中
* 恢复到Threadlocl中,继续执行之前的事务。
* 这个就是事务挂起和唤醒,其实很简单的
*
* 而下面的这个方法虽然是挂起事务,但是我们仔细分析可以知道它不仅仅是挂起事务的操作,因为这个方法也是在第一个事务
* 也会进来,第一个方法进来的传入的transaction是空的,就表示初始化事务的信息,就是除了连接信息以外的其他
* 信息的初始化而已,初始化完成过后返回一个SuspendedResourcesHolder对象,所以要清楚它干了什么事儿
*/
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
//这里是执行当事务挂起的时候的开发者自己注册的回调方法,但是如果是第一个事务开始地方调用的话
//获取的会调方法肯定是空的
/**
* 每段代码都要说半天??????
* 也就说如果出现了事物的传播,需要挂起之前的事务,那么这个挂起方法在执行挂起的时候需要
* 执行下挂起前的回调方法,当然了这个回调方法也是你自己开发者住注册的
* 通过 TransactionSynchronizationManager.registerSynchronization进行注册的
* 如果是第一个事务开始的地方来调用的这个方法,那么开发者注册的事务被挂起需要调用的回调根本都还没注册
* 所以就是空的
* 这个机制类似于spring的bean后置处理器一样,在bean的实例化前后,初始化前后调用的一个机制
*/
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
//如果事物tranaction不为空,那么就是出现了事物的传播,这里需要进行挂起
//就是清空resources
suspendedResources = doSuspend(transaction);
}
//初始化TransactionSynchronizationManager的其他信息
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
/**
* 最后构建一个SuspendedResourcesHolder对象返回
* 这个对象中有两点:
* 1.如果第一个事务方法,那么就是初始化的事务信息;
* 2.如果是传播事物,那么这里就是前面的的事务的信息(作为唤醒使用);
*/
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
// Neither transaction nor synchronization active.
return null;
}
}
/**
* Start a new transaction.
*/
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//将事务的信息封装到一个事物状态对象中
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//开启一个新的事务
doBegin(transaction, definition);
//初始化事务管理器的信息,当事务是新创建的是后初始化参数信息(其实都是Threadlocal信息)
//还有事务管理注册器的信息,默认为空,开发者可以自己注册synchronizations
prepareSynchronization(status, definition);
// 最后将事务的状态对象返回
return status;
}
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
throws TransactionException {
//唤醒事物的条件肯定是被唤起事物的对象不能为空
if (resourcesHolder != null) {
//之前挂起事务的事务对象(连接信息)
Object suspendedResources = resourcesHolder.suspendedResources;
if (suspendedResources != null) {
//唤醒之前的事务
doResume(transaction, suspendedResources);
}
List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
if (suspendedSynchronizations != null) {
TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
//如果开发者添加了事物挂起的事件方法,这里会去调用
doResumeSynchronization(suspendedSynchronizations);
}
}
}
异常回滚completeTransactionAfterThrowing
/**
* Handle a throwable, completing the transaction.
* We may commit or roll back, depending on the configuration.
* @param txInfo information about the current transaction
* @param ex throwable encountered
* 回滚事务,但是也不是,只有当异常为RuntimeException或者ERROR的时候才会去回滚,否则是commit
*/
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
/**
* This implementation of rollback handles participating in existing
* transactions. Delegates to {@code doRollback} and
* {@code doSetRollbackOnly}.
* @see #doRollback
* @see #doSetRollbackOnly
* 回滚事务
*/
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
processRollback(defStatus, false);
}
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
//事务回滚的时候,执行开发者注册的事务完成前的方法调用
triggerBeforeCompletion(status);
//这里是回滚到保存点,如果设置了保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
//如果是新开的事务,直接全部回滚
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
//触发事务完成后的回调(如果设置了)
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
//清除事务管理器的信息,并且如果事物传播了,那么唤醒之前的挂起的事物(如果存在之前挂起的事务)
//到这里的时候事务已经完成了,所以要清除当前事物,结束当前事物,并且唤起之前的事务(如果存在的话)
cleanupAfterCompletion(status);
}
}
/**
* Clean up after completion, clearing synchronization if necessary,
* and invoking doCleanupAfterCompletion.
* @param status object representing the transaction
* @see #doCleanupAfterCompletion
* 这个方法在事物回滚和提交的时候都会来调用
* 1.如果是新的事务,清除事务的信息,因为事务完成了,不管是回滚还是 提交;
* 2.如果是一个子事物并且存在了挂起的事务信息,进行唤醒之前的事务
*/
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
//如果是新的连接,就是新创建的连接事物,事物完成了,这里重置连接信息,清除连接信息
doCleanupAfterCompletion(status.getTransaction());
}
//如果事物状态对象中存在挂起的事务信息,进行唤醒
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
事务提交
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
//事务正常完成了触发提交前的一个操作,目前是空的实现,可能是提供给子类去实现的吧,目前也没有子类实现
prepareForCommit(status);
//触发事务提交前的事件(开发者自定义的)
triggerBeforeCommit(status);
//触发事物完成前的事件(开发者自定义的)
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
//这里是如果设置了保存点,提交到保存点
/**
* 但是目前mysql是不支持提交到保存点的,所以针对mysql
* 来说是空的实现,这个是spring的为了支持多数据库而设计的,万一有的数据库支持呢
*/
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
//如果是新开的事务,就是在创建事务的时候设置了一个true,如果事物出现了传播
//那么是从resource缓存中获取的,那么就不会提交这个事物
/**
* 什么意思呢?就是我们前面说了事物的传播机制了,那么传播机制中的条件之一就是在当前线程中
* 如果一个先从中出现了传播, 那么如果是REQUIREDS_NEW,那么就会新开一个新的事务,等
* 当前事物提交了过后唤醒之前的事务执行,但是如果是REQUIRED,那么不管传播多远,
* 都是在一个事物中完成的,所以这里的判断就是说如果出现了传播,必须是一个新的事务也就是
* 每个操作获取的事务对象是true才会提交,因为REQUIRED不管传播了多远,也就是多少个事物
* 都是需要在最后去提交的,所以这里的判断就是一般子事物不会提交, 等到最后来一起提交的意思
*/
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
//触发事务提交之后的事件(开发者自定义)
triggerAfterCommit(status);
}
finally {
//触发事务完成之后的事件(开发者自定义)
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
//这里有清除连接信息和唤起之前的事务的意思
cleanupAfterCompletion(status);
}
}
这个spirng的事务管理器是在太绕了,我这边只是胡乱一通的贴了代码的注释,作为以后遗忘了过来查看吧,本来想写的更清楚,但是最近是在忙的一塌糊涂,还要研究下源码以及写代码注释,再写笔记,所以是在没有太多时间来慢慢把思路写非常清楚,反正就贴上,如果有兴趣的可以根据我贴的代码或者思路去好好理下spring的事务,我把spring的代码注释和源码方在gitee上,地址是:https://gitee.com/scjava/spring5.2.x.git