Spring源码系列:事务原理

Spring源码系列:事务原理

  • 前言
  • 一. 事务案例
    • 1.1 项目结构和表结构
    • 1.2 代码编写部分
    • 1.3 配置文件
    • 1.4 运行结果
  • 二. 事务自定义标签解析(初始化)
    • 2.1 注册InfrastructureAdvisorAutoProxyCreator类
    • 2.2 事务标签的提取
    • 2.3 小总结
  • 三. 事务增强器TransactionInterceptor
    • 3.1 创建事务createTransactionIfNecessary
      • 3.1.1 获取事务
      • 3.1.2 事务构建(新事务的创建)
      • 3.1.3 处理已存在的事务
    • 3.2 回滚处理
      • 3.2.1 带保存点的回滚
        • 保存点案例
      • 3.2.2 不带保存点的回滚
      • 3.2.3 回滚后的信息清除
    • 3.3 事务提交
  • 四. 大总结(带流程图)

前言

事务是干什么用的?事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。 也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。

在了解事务的原理之前,我们先来看下一个简单的事务案例。

一. 事务案例

1.1 项目结构和表结构

我们先来看下项目的结构:红框部分
Spring源码系列:事务原理_第1张图片
其次,我的本地的数据库信息:

  • 数据库名称:test
  • 表名:user

表结构如下:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;

pom文件如下:

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-contextartifactId>
    <version>5.3.3version>
dependency>
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-txartifactId>
    <version>5.2.9.RELEASEversion>
dependency>
 <dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.39version>
dependency>
<dependency>
    <groupId>org.apache.commonsgroupId>
    <artifactId>commons-dbcp2artifactId>
    <version>2.9.0version>
dependency>
<dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>4.13version>
    <scope>testscope>
dependency>

1.2 代码编写部分

接下来我们看下代码部分:
User类:

package com.tx;

public class User {
    private int id;
    private String name;
    private int age;

    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

UserMapper类:

package com.tx;

import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;

public class UserMapper implements RowMapper {
    @Override
    public Object mapRow(ResultSet resultSet, int i) throws SQLException {
        User user = new User(resultSet.getInt("id"),
                resultSet.getString("name"),
                resultSet.getInt("age"));
        return user;
    }
}

UserService接口:

package com.tx;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation = Propagation.REQUIRED)
public interface UserService {
    void insert(User user) throws Exception;
}

UserService接口实现类UserServiceImpl

package com.tx;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.Types;

public class UserServiceImpl implements UserService {
    private JdbcTemplate jdbcTemplate;

    @Override
    public void insert(User user) throws Exception {
        jdbcTemplate.update("insert into user(id,name,age) values(?,?,?)",
                new Object[]{user.getId(), user.getName(), user.getAge()},
                new int[]{Types.INTEGER, Types.VARCHAR, Types.INTEGER});
        System.out.println("数据添加成功!");
        throw new RuntimeException("事务测试");
    }

    public void setDataSource(BasicDataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
}

Test类:

package com.tx;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("tx/user.xml");
        UserService userService = (UserService) context.getBean("userService");
        User user = new User(1, "LJJ", 22);

        userService.insert(user);
    }
}

1.3 配置文件

user.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xsi:schemaLocation="
   	http://www.springframework.org/schema/beans
   	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   	http://www.springframework.org/schema/tx
   	http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<tx:annotation-driven transaction-manager="transactionManager"/>

	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
		<property name="url" value="jdbc:mysql://localhost:3306/test"/>
		<property name="username" value="root"/>
		<property name="password" value="root"/>
	</bean>

	<bean id="userService" class="com.tx.UserServiceImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>

</beans>

1.4 运行结果

程序运行后如下图所示
Spring源码系列:事务原理_第2张图片
同时数据库中的数据并没有插入:可见程序回滚了。
Spring源码系列:事务原理_第3张图片

若我将下述代码注释掉:

throw new RuntimeException("事务测试");

此刻再运行,结果如下:
Spring源码系列:事务原理_第4张图片
再看下数据库中是否插入成功:
Spring源码系列:事务原理_第5张图片

注意:

Spring默认情况下的事务处理只针对RuntimeException方法进行回滚。

Mysql事务相关的知识,可进传送门Mysql技术内幕(四)–Mysql事务和备份

二. 事务自定义标签解析(初始化)

在学习AOP原理的时候,也是从XML配置入手,和AOP有关的配置文件为:

<aop:aspectj-autoproxy/>

那么同理,在本文的事务案例中,我们可以看到这么一个配置标签:

<tx:annotation-driven transaction-manager="transactionManager"/>

它作为事务的开关,因此我们从该配置作为入口进行深入学习。

有了前车之鉴,AOP对应的处理器为AopNamespaceHandler,那么事务对应的处理器是不是TxNamespaceHandler呢?搜一搜还真有!
Spring源码系列:事务原理_第6张图片

我们来看下里面的init方法:

public class TxNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}
}

啥意思呢?也就是根据自定义标签的使用规则,当遇到tx:annotation-driven标签的时候,Spring就会使用AnnotationDrivenBeanDefinitionParserparse()函数进行解析:

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		registerTransactionalEventListenerFactory(parserContext);
		String mode = element.getAttribute("mode");
		if ("aspectj".equals(mode)) {
			registerTransactionAspect(element, parserContext);
			if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
				registerJtaTransactionAspect(element, parserContext);
			}
		}
		else {
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}
}

由于Spring中的事务是以AOP为基础的,因此这里会对mode属性进行判断,是否使用AspectJ的方式进行事务的切入。若需要,配置如下:

<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>

本文以默认的动态代理的分支进行讲解。

2.1 注册InfrastructureAdvisorAutoProxyCreator类

AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
↓↓↓↓↓↓
private static class AopAutoProxyConfigurer {
	public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
		// 1.注册AOP的入口类
		AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
		String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
		if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
			Object eleSource = parserContext.extractSource(element);
			// 2.创建TransactionAttributeSource类型的bean ,即@Transactional注解的属性封装
			RootBeanDefinition sourceDef = new RootBeanDefinition(
					"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
			sourceDef.setSource(eleSource);
			sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
			// 3.创建TransactionInterceptor类型的bean,即AOP的调用链
			RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
			interceptorDef.setSource(eleSource);
			interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			// 4.拿到transaction-manager属性的值,参考
			registerTransactionManager(element, interceptorDef);
			interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
			String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
			// 5.创建TransactionAttributeSourceAdvisor
			RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
			advisorDef.setSource(eleSource);
			advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
			advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
			// 6.若配置了order属性,则加入到bean中
			if (element.hasAttribute("order")) {
				advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
			}
			parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
			// 7.创建 CompositeComponentDefinition
			CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
			compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
			compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
			compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
			parserContext.registerComponent(compositeDef);
		}
	}
}

此时我们来看下第一步代码:

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

点进去我发现,这个方法看起来非常非常的眼熟,如图:
Spring源码系列:事务原理_第7张图片
registerAutoProxyCreatorIfNecessary()函数的主要作用是注册了一个InfrastructureAdvisorAutoProxyCreator类。其类图关系如下:
Spring源码系列:事务原理_第8张图片
到这里,就和AOP的实现原理非常的相似了,传送门:Spring源码系列:AOP实现,从2.2节开始。

那么本篇文章为了连贯性,就以文字的形式再来回顾以下这里的实现:

  1. 由于InfrastructureAdvisorAutoProxyCreator类是BeanPostProcessor接口的子类,因此会调用postProcessAfterInitialization()方法。
  2. 其中会找到指定bean对应的增强器。
  3. 根据增强器创建对应的代理。

也因此说Spring事务是在AOP的基础上实现的。

但是出现分支点的代码在以下阶段:匹配候选增强器(过滤阶段)

/**
 * @param advisor:增强对象
 * @param targetClass:目标类
 * @param hasIntroductions:是否含有引介增强
 * @return
 */
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	// 1.如果是引介增强,则调用IntroductionAdvisor的getClassFilter.matches方法判断是否匹配
	if (advisor instanceof IntroductionAdvisor) {
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	} else if (advisor instanceof PointcutAdvisor) {
		// 2.如果是普通增强,调用canApply方法判断是否匹配
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	} else {
		return true;
	}
}

我们知道canApply函数需要传入一个增强Advisor对象。此时此刻,大家可以回顾下2.1小节最初放出的源码的第五步。创建了个BeanFactoryTransactionAttributeSourceAdvisor类型的实例。而其作为PointcutAdvisor类的一个子类,因此上述canApply函数会走第二个if分支

那么此时此刻,这个pca.getPointcut()函数返回的对象到底是啥呢?来看下这个方法的实现类:Spring源码系列:事务原理_第9张图片
本篇文章可是围绕着事务来讲的呀,那毫无疑问的,咱们根据名字就知道肯定看上图中红框类TransactionAttributeSourceAdvisor

public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null);
		}
	};
	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}
}

毫无疑问getPointcut函数返回的是TransactionAttributeSourcePointcut对象。


此时我们继续看canApply方法:

// 获取目标类以及父类的所有的方法,进行一一匹配,查看方法和类上是否有事务注解,有的话就直接返回。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	// ...省略
	for (Class<?> clazz : classes) {
		// 通过反射获取目标类的所有方法,进行逐一检测
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		// 获取所有方法(包括父类),任意一个匹配即返回true
		for (Method method : methods) {
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					// 关注这行代码
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}

我们关注到matches函数,这里调用的是子类TransactionAttributeSourcePointcut(通过getPointcut函数返回的)中的实现:

@Override
public boolean matches(Method method, Class<?> targetClass) {
	// 自定义标签解析的时候引入
	TransactionAttributeSource tas = getTransactionAttributeSource();
	return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

我们来关注下getTransactionAttribute函数:
Spring源码系列:事务原理_第10张图片
毫无疑问的,我们关注AbstractFallbackTransactionAttributeSource类中的实现:

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
	if (method.getDeclaringClass() == Object.class) {
		return null;
	}
	// 1.先尝试从缓存中取
	Object cacheKey = getCacheKey(method, targetClass);
	TransactionAttribute cached = this.attributeCache.get(cacheKey);
	if (cached != null) {
		// ...省略
	} else {
		// 2.若缓存中没有,那么去创建
		TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
		// ...省略
	}
}

到这里,才真正的走向事务标签的一个提取,也就是computeTransactionAttribute函数。我们先来总结下,这里花了大篇幅讲的内容,否则读者看着会比较混乱:

  1. 由于InfrastructureAdvisorAutoProxyCreator类是BeanPostProcessor接口的子类,因此会调用postProcessAfterInitialization()方法。
  2. 其中会找到指定bean对应的增强器。
  3. 根据增强器创建对应的代理。
  4. 匹配的过程中,若定义了事务相关的标签,则会被(TransactionAttributeSourcePointcut类捕获到,然后通过matches函数创建对应的事务节点。
  5. 也就是getTransactionAttribute()函数,其中主要通过computeTransactionAttribute()函数来创建。

那么接下来也就是关于事务原理的一个主流程了。

2.2 事务标签的提取

computeTransactionAttribute函数:

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
	// 1.非public方法的不可以增加事务
	if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
		return null;
	}
	Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
	// 2.查看方法中是否存在事务声明
	TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
	if (txAttr != null) {
		return txAttr;
	}
	// 2.查看方法所在的类中是否存在事务声明
	txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
	if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
		return txAttr;
	}
	// 3.若存在接口,则到接口中去寻找
	if (specificMethod != method) {
		// 3.1 查找接口方法
		txAttr = findTransactionAttribute(method);
		if (txAttr != null) {
			return txAttr;
		}
		// 3.2 去接口的类中去寻找
		txAttr = findTransactionAttribute(method.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}
	}

	return null;
}

这个函数的目的一目了然:事务属性的获取,其来源可能有三种:

  • 方法上。
  • 类上。
  • 类的接口上。

同时我们也可以看到,三种方式都是委派findTransactionAttribute函数去执行匹配:

public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {
	protected TransactionAttribute findTransactionAttribute(Method method) {
		return determineTransactionAttribute(method);
	}
	↓↓↓↓↓↓↓↓
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		// this.annotationParsers在 AnnotationTransactionAttributeSource 类初始化的时候,就加入了
		// SpringTransactionAnnotationParser类。
		for (TransactionAnnotationParser parser : this.annotationParsers) {
			TransactionAttribute attr = parser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}
}

我们来看下TransactionAnnotationParser.parseTransactionAnnotation()函数:

public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		// 先判断当前类是否有@Transactional注解,有的话则进行属性的提取
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			// 进行属性的提取
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}
	↓↓↓↓↓↓↓↓
	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
		// 事务的传播行为
		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		// 事务隔离级别
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		// 事务的超时时间
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		String timeoutString = attributes.getString("timeoutString");
		Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
				"Specify 'timeout' or 'timeoutString', not both");
		rbta.setTimeoutString(timeoutString);
		// 事务的读写性
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		// 可选的限定描述符,指定使用的事务管理器
		rbta.setQualifier(attributes.getString("value"));
		rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
		
		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		// 一组异常类,遇到时回滚
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		// 一组异常类名,遇到回滚,类型为string[]
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		// 一组异常类,遇到不回滚
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		// 不会导致事务回滚的异常类名字数组
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}
}

到这里,就是对事务注解和相关属性的解析了。同时,事务的初始化工作也就结束了。

2.3 小总结

事务原理的前半部分是在AOP的基础上实现的:

  1. 寻找Spring中的候选增强器。
  2. 从候选增强器中进行匹配过滤时,会根据指定的类或者类中的方法是否含有对应的事务属性来匹配
  3. 若包含了@Transactional注解或者相关属性,那么它是和事务增强器匹配的,则会被事务功能修饰
  4. 那么根据AOP的实现原理,在执行相关代码的时候,会开启AOP代理
  5. BeanFactoryTransactionAttributeSourceAdvisor类作为Advisor的一个实现类,那么当代理调用的时候自然会调用该类的增强方法。

而在2.1小节的第一个源码块中,解析事务定义标签的时候,Spring又将TransactionInterceptor类注入了到了BeanFactoryTransactionAttributeSourceAdvisor中(承上启下的感觉)。

  1. 因此在调用事务增强器增强的代理类时,就会先对TransactionInterceptor进行增强。
  2. 也就是下文要继续讲的invoke方法。

如图:
Spring源码系列:事务原理_第11张图片

三. 事务增强器TransactionInterceptor

本文章的第二章节可以说主要围绕着事务的初始化工作来展开介绍,那么本环节则侧重于事务的业务实现了。我们来看下其invoke方法:

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
			@Override
			@Nullable
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
			@Override
			public Object getTarget() {
				return invocation.getThis();
			}
			@Override
			public Object[] getArguments() {
				return invocation.getArguments();
			}
		});
	}
}

从这里可以看出这么几点:

  • TransactionInterceptor类继承自MethodInterceptor类。而MethodInterceptor是个环绕通知,符合事务的开启、提交和回滚操作。
  • 最后的返回,交给父类TransactionAspectSupportinvokeWithinTransaction函数来执行。

我们来看下invokeWithinTransaction函数:

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {
	// 1.获取对应的事务属性源
	TransactionAttributeSource tas = getTransactionAttributeSource();
	// 2.获取对应的事务属性
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	// 3.找到对应的事务管理器
	final TransactionManager tm = determineTransactionManager(txAttr);
	// ...省略
	// 4.拿到目标方法的唯一标识
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	// 5.声明式处理
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// 6.根据事务传播行为,判断是否有必要创建一个事务
		TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
		Object retVal;
		try {
			// 7.执行被增强的方法
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// 8.抛异常了,则进行回滚
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			// 9.清除信息
			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);
			}
		}
		// 10.提交事务
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}
	// 编程式事务
	else {
		// ...省略
	}
}

上述代码用文字总结就是:

  1. 首先获取事务的属性。
  2. 加载配置中配置的transactionManager(事务管理器)。参考
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
  1. 不同的事务采用不同的处理逻辑。声明式 / 编程式 事务。
  2. 在目标方法执行前,获取事务并收集事务的信息。
  3. 执行目标方法。
  4. 若出现异常,进行回滚处理。
  5. 对事务信息进行清除。
  6. 提交事务,即结束。

那么对于事务功能的执行来说,最重要的是三个部分:事务的创建、回滚的处理、事务的提交。我们先来看下创建事务的流程

3.1 创建事务createTransactionIfNecessary

入口代码为:

TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
↓↓↓↓↓↓↓↓
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
	// 1.若没有指定名称,则使用方法的唯一标识来封装 txAttr。(拿到事务的名称)
	// TransactionAttribute:txAttr 由获取事务属性的时候生成,用于数据的承载。
	if (txAttr != null && txAttr.getName() == null) {
		txAttr = new DelegatingTransactionAttribute(txAttr) {
			@Override
			public String getName() {
				return joinpointIdentification;
			}
		};
	}
	// 2.通过事务管理器获得一个事务的状态信息 (拿到事务的状态)
	TransactionStatus status = null;
	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");
			}
		}
	}
	// 3.根据指定的名称和status构建一个 TransactionInfo 事务信息存储对象。
	return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

我们来看下第二步status = tm.getTransaction(txAttr);这段核心代码,Spring主要在这段代码中来进行事务的一些准备工作。比如事务的获取和信息的构建:

status = tm.getTransaction(txAttr);
↓↓↓↓↓↓↓↓
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
		throws TransactionException {
	TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
	// 1.创建事务实例
	Object transaction = doGetTransaction();
	boolean debugEnabled = logger.isDebugEnabled();
	// 2.判断当前线程是否存在事务
	if (isExistingTransaction(transaction)) {
		// 若存在事务,返回即可
		return handleExistingTransaction(def, transaction, debugEnabled);
	}
	// 3.事务超时验证
	if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
		throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
	}
	// 4.如果当前线程不存在事务,但是事务船舶类型被声明为 PROPAGATION_MANDATORY ,抛异常
	if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		throw new IllegalTransactionStateException(
				"No existing transaction found for transaction marked with propagation 'mandatory'");
	}
	// 5.新建事务
	else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
		// 空挂起
		SuspendedResourcesHolder suspendedResources = suspend(null);
		if (debugEnabled) {
			logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
		}
		try {
			// 6.构建事务
			return startTransaction(def, transaction, debugEnabled, suspendedResources);
		}
		// ...省略
	}
	// ...省略
}

3.1.1 获取事务

我们来看下第一步,关于事务实例的获取过程:

// 抽象方法,具体交给子类实现来执行
Object transaction = doGetTransaction();

最终的实现则交由DataSourceTransactionManager类来执行:

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
	@Override
	protected Object doGetTransaction() {
		// 主要创建一个基于JDBC的事务实例
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		// 若当前线程已经记录了数据库连接,那么使用原有的连接
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		// false表示非新创建连接
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}
}

上述代码本身并没有什么可讲的,因为毕竟是在事务已存在的情况下才会走的逻辑。但是事务不存在的情况下,就会着手于事务的创建了,按照上述的代码流程,则:

  1. 若当前线程存在事务,则转向嵌套事务的处理。
  2. 否则进行事务超时设置验证。
  3. 事务传播行为的验证。
  4. 构建事务。

3.1.2 事务构建(新事务的创建)

事务的获取,返回的结果不为null的前提是什么?是当前线程的事务已经存在了。那么事务的构建流程这里想必是没有展开。那么我们来看下第四步,关于事务的构建代码:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
	startTransaction(def, transaction, debugEnabled, suspendedResources);
	
	private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
	
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		// 1.构建 DefaultTransactionStatus 实例对象
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		// 2.完善事务信息,包括设置ConnectionHolder。隔离级别、timeout等信息
		doBegin(transaction, definition);
		// 3.主要将当前的事务信息绑定到当前线程的ThreadLocal中
		prepareSynchronization(status, definition);
		return status;
	}
}

我们来看下第二步,事务信息的完善处理:

@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;

	try {
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			Connection newCon = obtainDataSource().getConnection();
			if (logger.isDebugEnabled()) {
				logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
			}
			txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		}

		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		// 获取数据库的连接
		con = txObject.getConnectionHolder().getConnection();
		// 隔离级别的设置
		Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
		txObject.setPreviousIsolationLevel(previousIsolationLevel);
		txObject.setReadOnly(definition.isReadOnly());
		// 自动提交的设置,由Spring来控制提交
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			if (logger.isDebugEnabled()) {
				logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
			}
			con.setAutoCommit(false);
		}
	
		prepareTransactionalConnection(con, definition);
		// 设置判断当前线程是否存在事务的依据
		txObject.getConnectionHolder().setTransactionActive(true);

		int timeout = determineTimeout(definition);
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		// Bind the connection holder to the thread.
		if (txObject.isNewConnectionHolder()) {
			// 将当前获取到的连接绑定到当前线程
			TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
		}
	}
	// ...省略
}

我们在这段代码中发现了Spring开始尝试对数据库连接的获取,也因此我们可以说事务是从这个函数开始的。 这段代码的主要工作:

  1. 尝试获取连接。
  2. 设置隔离级别和只读标识。
  3. 更改默认的提交方式,改为由Spring来控制。
  4. 设置标记位,标识当前连接已经被事务激活。
  5. 设置过期时间。
  6. connectionHolder绑定到当前线程。

到这里为止,讲的内容都是围绕着新建事务的创建过程来展开的,总体可以分为三步:

  • 事务对象的获取 / 创建及数据库连接的获取。
  • 设置相关的数据库属性,如隔离级别等。
  • 将获得的事务对象和当前线程进行信息绑定。

3.1.3 处理已存在的事务

我们知道,Spring中事务的类型有这么几种:

  • PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,就新建一个事务。

那么如同PROPAGATION_REQUIRES_NEWPROPAGATION_NESTED等类型,Spring又是如何处理的呢?还记得getTransaction函数中的这段代码吗?

return handleExistingTransaction(def, transaction, debugEnabled);

我们来分析下,对于已经存在的事务,Spring是如何处理的(而这段代码诠释了Spring事务类型对应的语义):

private TransactionStatus handleExistingTransaction(
		TransactionDefinition definition, Object transaction, boolean debugEnabled)
		throws TransactionException {
	// ...省略
	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) {
			resumeAfterBeginException(transaction, suspendedResources, beginEx);
			throw beginEx;
		}
	}
	// 嵌套事务的处理
	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()) {
			DefaultTransactionStatus status =
					prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
			status.createAndHoldSavepoint();
			return status;
		}
		else {
			// 类似于JTA这类情况是不能够使用保存点操作的,因此建立新的事务
			return startTransaction(definition, transaction, debugEnabled, null);
		}
	}
	// ...省略
	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

3.2 回滚处理

上述代码我们主要围绕着事务的创建来展开的,如图红框所示:
Spring源码系列:事务原理_第12张图片

如果事务期间,发生了特定的错误,那么事务将会进行回滚,那么Spring是怎么对数据进行修复的呢?

completeTransactionAfterThrowing(txInfo, ex);
↓↓↓↓↓↓
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
	// 1.当抛出异常的时候,应该先判断当前是否存在事务(前提,毕竟没有事务,我回滚的意义是啥?)
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
		if (logger.isTraceEnabled()) {
			logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
					"] after exception: " + ex);
		}
		// 判断 是否进行默认的回滚。 依据:抛出的异常是否为RuntimeException或者Error类型
		if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
			try {
				// 根据TransactionStatus信息进行回滚处理
				txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
			}
			// ..catch
		}
		else {
			// 若不满足回滚条件,即使抛出异常了,也进行提交
			try {
				txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
			}
			// ..catch
		}
	}
}

我们来看下rollbackOn函数:

public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
	@Override
	public boolean rollbackOn(Throwable ex) {
		return (ex instanceof RuntimeException || ex instanceof Error);
	}
}

也因此在事务案例章节中,我们手动抛出了个RuntimeException异常,目的就是触发事务的回滚操作。

当然,若希望回滚触发的异常条件做出改变怎么办?很简单,在注解中添加对应的属性即可,如:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)

言归正传,我们需要关注Spring是如何进行回滚的,那么关键的我们来看第二步:

txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
↓↓↓↓↓↓
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
	@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 {
				// 1.激活所有的 TransactionSynchronization(自定义触发器) 中对应的方法
				triggerBeforeCompletion(status);
				// 2.若有保存点,那么当前线程的事务会退到保存点
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}
					status.rollbackToHeldSavepoint();
				}
				// 3.若当前事务为独立的新事务,则直接返回
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction rollback");
					}
					doRollback(status);
				}
				else {
					// 4.若当前事务不是独立的事务,那么只能标记状态,等到事务链执行完毕后统一回滚
					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;
			}
			// 激活所有的 TransactionSynchronization(自定义触发器)  中对应的方法
			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);
		}
	}
}

可见回滚操作主要做了这么几个重要的事情:

  1. 自定义触发器的调用(包括回滚前、回滚后)。
  2. 回滚逻辑的处理。
  3. 回滚后的信息清除。

3.2.1 带保存点的回滚

从上述代码的函数名称上,我们可以主要看rollbackToHeldSavepoint这个函数:

status.rollbackToHeldSavepoint();
↓↓↓↓↓
public void rollbackToHeldSavepoint() throws TransactionException {
	Object savepoint = getSavepoint();
	if (savepoint == null) {
		throw new TransactionUsageException(
				"Cannot roll back to savepoint - no savepoint associated with current transaction");
	}
	// 通过事务管理器,将程序回滚至指定的保存点
	getSavepointManager().rollbackToSavepoint(savepoint);
	// 通过事务管理器,释放保存点
	getSavepointManager().releaseSavepoint(savepoint);
	setSavepoint(null);
}

rollbackToSavepoint接口有三种实现,这里我们主要看JdbcTransactionObjectSupport
在这里插入图片描述
因为我们使用的是JDBC的方式进行数据库连接,

public abstract class JdbcTransactionObjectSupport implements SavepointManager, SmartTransactionObject {
	@Override
	public void rollbackToSavepoint(Object savepoint) throws TransactionException {
		ConnectionHolder conHolder = getConnectionHolderForSavepoint();
		try {
			conHolder.getConnection().rollback((Savepoint) savepoint);
			conHolder.resetRollbackOnly();
		}
		catch (Throwable ex) {
			throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
		}
	}
}

此时rollback又有多种实现:
Spring源码系列:事务原理_第13张图片
此时我们关注第一个实现类ConnectionImpl

备注:

ConnectionImplConnection接口的一个实现类,而本案例当中,由于我引入了pom依赖mysql-connector-java,因此这里走的是ConnectionImpl.rollback()函数,不同的实现类有着不同的回滚逻辑。这里就不做展开了,主要通过一个保存点案例带大家过一遍用法。

保存点案例

读者请在第一章节的案例基础上进行更改,UserServiceImpl类:

@Override
    public void insert(User user) throws Exception {
        DefaultTransactionStatus transactionStatus = (DefaultTransactionStatus) TransactionAspectSupport.currentTransactionStatus();
        // 保存点1
        transactionStatus.createAndHoldSavepoint();

        jdbcTemplate.update("insert into user(id,name,age) values(?,?,?)",
                new Object[]{user.getId(), user.getName(), user.getAge()},
                new int[]{Types.INTEGER, Types.VARCHAR, Types.INTEGER});
		// 保存点2
        // transactionStatus.createAndHoldSavepoint();
        jdbcTemplate.update("insert into user(id,name,age) values(?,?,?)",
                new Object[]{user.getId() + 1, "Hello", 100},
                new int[]{Types.INTEGER, Types.VARCHAR, Types.INTEGER});
		// 保存点3
        // transactionStatus.createAndHoldSavepoint();
        throw new RuntimeException("事务测试");
    }

执行代码后,分三种情况:

  • 仅保留保存点1:数据库插入0条数据。
  • 仅保留保存点2:数据库插入1条数据。
  • 仅保留保存点3:数据库插入2条数据。

可见默认情况下,回滚将回到最后一个保存点所在的位置。

3.2.2 不带保存点的回滚

若不带保存点,那么将走doRollback()函数:

doRollback(status);
↓↓↓↓↓↓↓
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
	protected void doRollback(DefaultTransactionStatus status) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();	
        // 获取数据库连接
        Connection con = txObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            this.logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
        }
        try {
        	// 交给数据库来进行回滚
            con.rollback();
        } catch (SQLException var5) {
            throw new TransactionSystemException("Could not roll back JDBC transaction", var5);
        }
    }
}

这部分代码比较通俗易懂,就是将回滚的任务委派给数据库本身来执行。而本篇文章主要讲Spring事务的实现机制,因此这里不再赘述(后期准备对数据库进行复习,然后回滚也会做详细的展开)。

3.2.3 回滚后的信息清除

回滚逻辑执行结束之后,无论回滚操作是否成功,我们都需要做后续的收尾工作,我们来看下代码:

cleanupAfterCompletion(status);
↓↓↓↓↓↓
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
	// 1.设置事务的状态置为完成,目的是为了避免重复调用
	status.setCompleted();
	// 2.若当前事务是新的同步状态,那么需要将 绑定到当前线程的事务信息清除
	if (status.isNewSynchronization()) {
		TransactionSynchronizationManager.clear();
	}
	// 3.如果是新事务,那么需要做一些资源的清除工作
	if (status.isNewTransaction()) {
		doCleanupAfterCompletion(status.getTransaction());
	}
	// 4.若事务执行前,还存在挂起的事务,那么当前事务执行结束后,恢复挂起的事务
	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());
	}
}

我们来看下资源清除工作做了些什么操作:

// 接口,具体实现交给子类
doCleanupAfterCompletion(status.getTransaction());
↓↓↓↓↓↓
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
	@Override
	protected void doCleanupAfterCompletion(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		// 1.将数据库连接从当前线程中解除绑定
		if (txObject.isNewConnectionHolder()) {
			TransactionSynchronizationManager.unbindResource(obtainDataSource());
		}
		// 2.释放连接
		Connection con = txObject.getConnectionHolder().getConnection();
		try {
			// 3.恢复数据库连接的自动提交属性(之前设置事务的时候,是将其交给了Spring来控制)
			if (txObject.isMustRestoreAutoCommit()) {
				con.setAutoCommit(true);
			}
			// 4.重置数据库连接
			DataSourceUtils.resetConnectionAfterTransaction(
					con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
		}
		catch (Throwable ex) {
			logger.debug("Could not reset JDBC Connection after transaction", ex);
		}
		// 5.若当前事务是新创建的事务,那么在事务完成的时候,释放数据库连接
		if (txObject.isNewConnectionHolder()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
			}
			DataSourceUtils.releaseConnection(con, this.dataSource);
		}

		txObject.getConnectionHolder().clear();
	}
}

总结下就是:

  • 回滚操作结束后,对事务的完成做收尾工作。
  • 之前有事务被挂起了的,那么Spring恢复它。
  • 释放数据库的连接,重置相关信息。

最后,回滚操作到这这里也结束了(若出现异常的情况下)。无论程序是走了回滚操作还是正常执行。最后必定会将事务进行提交,只有事务提交上去,程序才算真正的跑完。

3.3 事务提交

我们来看下源码:

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
	protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		// 进行事务提交的前提,是事务存在
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}
}
↓↓↓↓↓↓commit↓↓↓↓↓↓
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
	@Override
	public final void commit(TransactionStatus status) throws TransactionException {
		// 1.事务已经提交完成了,那么这里肯定不能重复提交,抛出异常
		if (status.isCompleted()) {
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}
		// 2.若事务已经被标记回滚,那么不能够尝试提交事务,直接回滚
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}
		// 同上
		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			processRollback(defStatus, true);
			return;
		}
		// 3.处理事务的提交
		processCommit(defStatus);
	}
	↓↓↓↓↓↓processCommit↓↓↓↓↓↓
	private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				// 添加 TransactionSynchronization 中对应方法的前后调用
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;
				// 若存在保存点,则清除保存点信息(事务提交了,保存点存在的意义也就没了)
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					status.releaseHeldSavepoint();
				}
				// 若没有保存点,是个独立的新事务,那么直接提交即可
				else if (status.isNewTransaction()) {
					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
			catch (RuntimeException | Error ex) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				// 提交过程中出现异常,回滚
				doRollbackOnCommitException(status, ex);
				throw ex;
			}
			try {
				triggerAfterCommit(status);
			}
			finally {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
			}

		}
		finally {
			cleanupAfterCompletion(status);
		}
	}
}

从上述代码可以发现,即使事务的整个过程到达了最后的提交阶段,但也并不是无脑直接提交的。而是考虑了很多方面:

  • 当事务状态中含有保存点的信息,那么不会提交事务。
  • 当事务并非新事务的时候,也不会执行提交操作。
  • 只有符合:没有保存点、是独立的新事务。此时会将事务提交委派给数据库来执行。

上述第二点的目的是什么?

  • 主要考虑内嵌事务的存在。对于内嵌事务,Spring的处理是在内嵌事务开始之前创建一个保存点。
  • 一旦内嵌事务出现异常,那么会根据保存点进行回滚。
  • 若正常运行,内嵌事务也不会单独提交,而是由最外层事务负责提交。

若正常提交的时候,根据上述代码进行doCommit操作,而这里同理事务的回滚(不带保存点),执行逻辑交给数据库连接的API来执行:

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
	@Override
	protected void doCommit(DefaultTransactionStatus status) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
		// 获取数据库连接
		Connection con = txObject.getConnectionHolder().getConnection();
		if (status.isDebug()) {
			logger.debug("Committing JDBC transaction on Connection [" + con + "]");
		}
		try {
			// 由数据库连接来控制事务的提交操作。
			con.commit();
		}
		catch (SQLException ex) {
			throw translateException("JDBC commit", ex);
		}
	}
}

到这里事务的整套流程也就完成了,接下来放流程图做总结。

四. 大总结(带流程图)

你可能感兴趣的:(Spring,Java,java,spring,后端)