基础
Spring事务抽象的关键是事务策略的概念。事务策略由org.springframework.transaction.PlatformTransactionManager接口定义的,如下所示:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
它主要是一个服务提供者接口(service provider interface, SPI),因为PlatformTransactionManager是一个接口,所以它可以根据需要轻松地Mock或存根。它不绑定到查找策略,比如JNDI。典型的实现就是我们常用的DataSourcePlatformTransactionManager。
由该接口的方法抛出的TransactionException异常是一个未检查异常(也就是说它扩展自RuntimeException)
getTransaction(…)方法返回的是一个TransactionStatus,它完全取决于TransactionDefinition这个入参。如果当前调用堆栈中存在匹配的事务,则返回的TransactionStatus可能表示一个新事务,当然也可能表示一个现有事务。后一种情况的含义是,与Java EE事务上下文一样,事务状态与执行线程相关联。
TransactionDefinition接口中指定了:
- Propagation:通常,在事务作用域内执行的所有代码都在该事务中运行。但是,你可以通过该配置指定行为,当事务方法在事务上下文已经存在时执行时应该如何操作。例如,代码可以在现有事务中继续运行(通常情况下),或者可以挂起现有事务并创建一个新事务。
- Isolation:此事务与其他事务的工作隔离的程度。例如,该事务能否看到来自其他事务的未提交写操作?
- Timeout:此事务在超时并由底层的事务基础设施自动回滚之前,可以运行多长时间。
- Read-Only:当代码读取但不修改数据时,可以使用只读事务。在某些情况下,只读事务是一种有用的优化,比如在使用Hibernate时。
TransactionStatus接口为需要事务功能的代码提供了一种简单的方法来控制事务执行和事务状态查询。这些概念应该很熟悉,因为它们对所有事务API都是通用的。下面的清单显示了TransactionStatus接口:
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
无论您在Spring中选择声明式事务管理还是编码式事务管理,定义正确的PlatformTransactionManager实现都是至关重要的。您通常通过依赖项注入来定义此实现。
PlatformTransactionManager实现通常需要了解它们工作的环境:JDBC、JTA、Hibernate等等。比如:
<!--配置数据源-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close" >
<constructor-arg name="configuration" ref="hikariConfig" />
</bean>
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig" >
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/xxx/>
<property name="username" value="userName"/>
<!--<property name="schema" value="pwd" />-->
<property name="password" value="za_dev_fcptel_f06e96" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource" />
</bean>
1.准备
<!--配置数据源-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close" >
<constructor-arg name="configuration" ref="hikariConfig" />
</bean>
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig" >
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/xxx/>
<property name="username" value="userName"/>
<!--<property name="schema" value="pwd" />-->
<property name="password" value="za_dev_fcptel_f06e96" />
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource" />
</bean>
<!--启动注解驱动事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
##Mysqld的驱动程序
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
##数据源实现:HikariCP,类比于DBCP,c3p0,但是效率更高
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.0</version>
</dependency>
##Spring对Java原生数据库操作的封装,JdbcTemplate
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
2.annotation-driven
TX命名空间属于自定义命名空间,因此Spring在源代码中,通过TxNamespaceHandler,在其init方法中,完成了对其对应的BeanDefinitionParser的注册:
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
当Spring在解析annotation-driven这个BeanDefinition时,NamespaceHandlerResolver会根据TX这命名空间,返回一个TxNamespaceHandler实例,最终元素的解析,则是交给了AnnotationDrivenBeanDefinitionParser来做。
AnnotationDrivenBeanDefinitionParser是一个BeanDefinitionParser,它的核心方法就是parser(…):
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册监听,可以忽略
registerTransactionalEventListenerFactory(parserContext);
// 根据<tx:annotation-driven mode="">中的mode属性,决定实现模式,是使用AspectJ还是代理模式?
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
}
我们仅以默认mode来解析:
public static final String TRANSACTION_ADVISOR_BEAN_NAME =
"org.springframework.transaction.config.internalTransactionAdvisor";
//该类以内部类的形式存在~
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 1.0 首先注册一个BeanPostProcessor,用于在Bena实例化时进行事务代理
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
// 2.0 查找当前BeanFactory是否已经有事务增强器【即TRANSACTION_ADVISOR_BEAN_NAME这个BeanName的BeanDefinition】的BeanDefinition存在了
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// 2.1 创建一个TransactionAttributeSource的BeanDefinition.
// TransactionAttributeSource是一个策略接口,它由TransactionInterceptor使用,用于检索元数据
// 它的实现知道如何获取到事务属性,无论是从配置,还是源级别的元数据属性(如Java 5的注解)或其他任何地方。
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 创建一个TransactionInterceptor 的BeanDefinition.
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 创建一个TransactionAttributeSourceAdvisor的BeanDefinition.
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);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
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);
}
}
}
概述:该方法的主要工作,是注册BeanPostProcessor,,用于代理事务方法,然后就是注册几个BeanDefnition,都比较重要,所以分开讲
注册BeanPostProcessor
我们追踪进AopNamespaceUtils:
public abstract class AopNamespaceUtils {
public static void registerAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册一个自动代理的BeanPostProcessor,其实就是InfrastructureAdvisorAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 解析proxy-target-class和expose-proxy,并设置BeanDefinition
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册以消息监听,不需关注
registerComponentIfNecessary(beanDefinition, parserContext);
}
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
我们继续追踪:
public abstract class AopConfigUtils {
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 注册或者升级一个InfrastructureAdvisorAutoProxyCreator
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
}
如果了解AOP的底层,那么这里其实很Easy。首先判断BeanFactory中是否存在BeanName是AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition,如果存在,那么判断到底谁的优先级高,选用高优先级的;而如果不存在,那么定义一个InfrastructureAdvisorAutoProxyCreator的BeanDefinition,并以AUTO_PROXY_CREATOR_BEAN_NAME为BeanName注册到BeanFactory上。
InfrastructureAdvisorAutoProxyCreator是一个SmartInstantiationAwareBeanPostProcessor,该后置处理器可以应对循环引用,并会在Bean的实例化前后、初始化前后以及BeanDefinitio被Merged后,调用对应的回调方法。更多的请看Aop图解
注册AnnotationTransactionAttributeSource的BeanDefinition
AnnotationTransactionAttributeSource的父类是TransactionAttributeSource:
public interface TransactionAttributeSource {
/**
* 返回给定Method的事务属性【transaction attribute】,如果是非事务方法,那么返回null
*/
@Nullable
TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
}
TransactionAttributeSource是一个策略接口,其实现知道如何获取到事务属性,无论是从配置,还是从事务注解,或者是其他地方。
AnnotationTransactionAttributeSource是一个具体的策略实现,如其名,它返回的是基于注解形式的事务属性【TransactionAttribute】。
但是Spring支持多种平台框架的事务,比如EJB的事务,还有Java原生事务,因此抽象了一个TransactionAnnotationParser策略接口,该接口负责解析已知的注解事务类型,比如:
- JtaTransactionAnnotationParser,用于解析javax.transaction.Transactional
- Ejb3TransactionAnnotationParser,用于解析javax.ejb.TransactionAttribute
- SpringTransactionAnnotationParser,用于解析@Transactional,它是Spring原生的
那么TransactionAttribute又是什么呢?他就是事务属性,通俗而言,就是事务的配置项,我们来具体的看由原生@Transaction注解所解析出的RuleBasedTransactionAttribute:
/**
* TransactionAttribute实现,它通过应用一些回滚规则(包括正回滚规则和负回滚规则)
* 来判断给定的异常是否应该导致事务回滚。如果没有与异常相关的规则,它的行为类似于
* DefaultTransactionAttribute(回滚RuntimeException)。
*/
public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute implements Serializable {
@Nullable
//Rollback的规则
private List<RollbackRuleAttribute> rollbackRules;
/**
* 其父类DefaultTransactionAttribute中,对所有运行时异常进行回滚
* RuleBasedTransactionAttribute在其父类基础上,增加了规则匹配,如果规则匹配成功,
*/
@Override
public boolean rollbackOn(Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
}
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
// 根据RollbackRuleAttribute的深度属性,取深度最低的回滚规则
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
// 如果没有匹配的回滚规则,那么按照默认行为回滚(即对运行时异常和Error回滚)
if (winner == null) {
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex);
}
// 如果匹配的混滚规则是一个NoRollbackRuleAttribute,那么说明无需回滚,否则回滚
return !(winner instanceof NoRollbackRuleAttribute);
}
}
RuleBasedTransactionAttribute是TransactionAttribute的实现,它的功能很全面,不仅记录了事务注解上的配置信息,还允许支持规则匹配的回滚方案。综合而言,TransactionAttribute就是事务相关的配置项的聚合,它承载着诸如propagation、isolation、timwout、readOnly等等配置信息
总结:AnnotationTransactionAttributeSource是一个具体的策略实现,用于解析方法上的事务注解,并将其转换为一个TransactionAttribute对象。
注册TransactionInterceptor的BeanDefinition
TransactionInterceptor是声明式事务管理的AOP Alliance MethodInterceptor:
PS:MethodInterceptor的父类是Advice,因此TransactionInterceptor也是一个增强!!!
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@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<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 适配到TransactionAspectSupport(父类)的invokeWithinTransaction方法上 ...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 如果TransactionAttribute为null,那么说明它不是事务方法
TransactionAttributeSource tas = getTransactionAttributeSource();
// 根据TransactionAttributeSource,获取该Method对应的TransactionAttribute,直白一点,就是该方法上的事务注解属性配置
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取当前BenaFactory中的事务管理器,我们配置文件配置的DataSourceTransactionManager是PlatformTransactionManager的实现
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 为该Method构造出一个全局唯一的连接点标识(比如:类.方法,样例是service.UserServiceImpl.save)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 如果是声明式事务
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal;
try {
// 这是一个环绕增强【around advice】:调用拦截器链中的下一个拦截器
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 异常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// TransactionInfo清理
cleanupTransactionInfo(txInfo);
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 如果是编程式事务
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
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);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
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;
}
}
}
}
TransactionInterceptor是一个比较重要的类,它亦是由@Transaction注解衍生的代理的拦截器链中的其中一个。TransactionInterceptor最重要的方法就是它的invoke()方法。
我们概述一下流程:
- 获取TransactionAttributeSource,并委托其检出当前调用方法的TransactionAttribute
- 加载配置的PlatformTransactionManager,我们例子中即是在配置文件配置的DataSourcePlatformTransactionManager
- 根据不同的事务处理方式:声明式事务 OR 编程式事务,应用不同的逻辑,我们只介绍声明式事务
- 创建事务,并生成TransactionInfo
- 调用链,执行目标方法
- 一旦出现异常,则回滚
- 清理TransactionInfo
- 提交事务
我们以声明式事务的场景,拆解功能:
Ⅰ.createTransactionIfNecessary
真正的方法实现,是在其父类中定义的:
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 如果事务属性中没有指定name,则使用全局唯一的连接点标识,来作为name。
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 调用PlatformTransactionManager的getTransaction方法,获取事务
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
}
该方法核心功能只有两个:⑴获取事务TransactionStatus⑵构建TransactionInfo
我们首先看如何获取事务TransactionStatus:
@Override
/**
* 传入的TransactionDefinition入参,其实就是前面根据Method解析出的TransactionAttribute,
* 它是TransactionDefinition的子类,主要承载事务的配置项
*/
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 查询事务,这里只是缓存的查询,即检查当前线程中是否存在事务,并封装进DataSourceTransactionObject中
Object transaction = doGetTransaction();
if (definition == null) {
// 如果入参给定的TransactionDefinition为NULL,则使用缺省值,即DefaultTransactionDefinition
definition = new DefaultTransactionDefinition();
}
// 当前线程是否存在事务
if (isExistingTransaction(transaction)) {
// 如果当前线程存在事务,则检查船舶机制,来找出采取什么行为
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 检查传入的超超时时间你是否小于-1,以避免非法的配置.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// 如果当前线程没有事物存在,那么检查传播机制,以确定使用什么方式来处理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// Spring仅仅支持PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED这几种传播机制
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// 创建“空”事务:没有实际事务,但可能同步。.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
private boolean nestedTransactionAllowed = false;
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// 根据是否允许事务嵌套,设置DataSourceTransactionObject的SavepointAllowed特性
txObject.setSavepointAllowed(nestedTransactionAllowed);
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
概述:
⒈获取事务
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
创建一个DataSourceTransactionObject,根据是否允许事务内嵌,设置其是否允许允许保存点。因为如果允许事务内嵌,那么当A事务方法调用B事务方法时,会先将A事务方法暂停,并开启一个B事务,待B事务结束,再恢复A事务。
事务中必然不可缺少数据库连接,在原生JDBC中,我们也是通过Connect来设置事务commit和rollback。接下来通过TransactionSynchronizationManager的getResource()方法,根据数据源【DataSource】获取一个ConnectionHolder,即数据库连接。
public abstract class TransactionSynchronizationManager {
// 线程私有的ThreadLocal
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 入参key是一个数据源对象,此处即是一个HikariDataSource (HikariPool-1)
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
private static Object doGetResource(Object actualKey) {
// 获取线程级resources缓存
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
// 根据传入的key,取出对应的应设置,其实就是事务对象
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
}
事务同步管理器【TransactionSynchronizationManager】负责维护线程与事务的关系。
注意,resources变量是一个ThreadLoacal类型的,因此它是线程私有变量。它缓存着该线程内,Key(在本例中即是一个HikariDataSource对象)与事务的映射关系。
getResource(key)完成的只是缓存的读取,并未真的创建事务或者开启数据库连接。如果给定的Key(在本例中即是一个HikariDataSource对象)并没有对应的事务缓存值,那么返回null,Spring会在下面依据事务是否存在,走不同的处理分支
⒉验证当前线程是否存在事务,如果存在,则转向嵌套事务的处理
⒊验证配置的事务超时时间是否<-1,如果小于,那么抛异常,因为这是非法的超时时间设置
⒋根据设置的传播机制,验证,Spring只支持PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED这三种传播机制
⒌suspend(null),空挂起,因为代码能走到这里,说明事务对象并不存在(否则早就转向嵌套事务处理分支了),因此入参硬编码的null
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
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);
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;
}
}
⒍创建事务,即DefaultTransactionStatus,此处只是设置一些参数,并没有
⒎doBegin,配置数据库相关的设置,比如超时时间、自动提交、数据库连接等等
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 从数据源中获取数据库连接,首先从PlatformTransactionManager中取出配置的DataSource
// 本例子中即是一个HikariDataSource,然后调用getConnection()获取Connection对象
// 这是一个完全Spring无关的技术
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 将刚才获取的数据库连接存入DataSourceTransactionObject中,并通过true,标识该数据库连接是新的
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 设置数据库的隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 如果需要,切换到手动提交。
// Spring将自动提交取消,而是全权由Spring管理是否commit
// 这在一些JDBC驱动程序中非常昂贵,所以我们不想做不必要的操作(例如,如果我们已经显式地配置了连接池来设置它)
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 如果设置read-only,那么执行“SET TRANSACTION READ ONLY” SQL语句
prepareTransactionalConnection(con, definition);
// 设置事务激活状态,该状态会用于判断当前线程是否存在事务
txObject.getConnectionHolder().setTransactionActive(true);
// 设置超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 通过事务同步管理器,将数据库连接的holder绑定到线程上.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
该方法是核心方法,概述而言:
⑴尝试获取数据库连接,如果DataSourceTransactionObject中并不存在数据库连接,那么就通过配置的DataSource获取一个Connection数据库连接,将其封装为ConnectionHolder,然后设置进DataSourceTransactionObject中进行保存
⑵设置数据库连接的隔离级别、超时时间、自动提交等
⑶设置激活状态位,标识当前连接已经被事务激活
⑷通过事务同步管理器【TransactionSynchronizationManager】,将数据库连接的ConnectionHolder绑定到线程的ThreadLocal变量上
⒏根据需要初始化事务同步。
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
definition.getIsolationLevel() : null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
}
}
通过事务同步管理器【TransactionSynchronizationManager】,将事务的相关信息,记录到当前线程的本地变量上。
public abstract class TransactionSynchronizationManager {
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 激活当前线程的事务同步。
// 事务同步管理器在事务开始和清理时设置该值
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
// 公开当前事务的name,其实就是:全路径类名.方法名,如con.xxx.service.UserService.save
// 事务同步管理器在事务开始和清理时设置该值
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 公开当前事务是否是read-only的
// 事务同步管理器在事务开始和清理时设置该值
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");
// 公开当前线程是否有实际处于Active的事务。
// 事务同步管理器在事务开始和清理时设置该值
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
}
logger.trace("Initializing transaction synchronization");
synchronizations.set(new LinkedHashSet<>());
}
}
如上,TransactionSynchronizationManager中声明了很多ThreadLocal变量,分别用于记录当前线程的事务相关信息。
Ⅱ.prepareTransactionInfo
当TransactionStatus和TransactionAttribute都准备好后,创建一个TransactionInfo,用于统一记录。
TransactionInfo中包含目标方法开始前的所有状态信息,一旦事务执行失败,Spring可以通过TransactionInfo中的信息进行回滚等后续操作
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<>("Current aspect-driven transaction");
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// 记录事务状态:TransactionStatus
txInfo.newTransactionStatus(status);
}
else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled()) {
logger.trace("No need to create transaction for [" + joinpointIdentification +
"]: This method is not transactional.");
}
}
// 我们总是将TransactionInfo绑定到线程,即使我们没有在这里创建一个新的事务。
// 这保证了即使这个切面没有创建任何事务,也能正确地管理TransactionInfo堆栈。
// 将该TransactionInfo,加入到上面的ThreadLocal类型的变量transactionInfoHolder上!!!
txInfo.bindToThread();
return txInfo;
}
我们主要看一下如何将TransactionInfo绑定到当前线程上:
protected final class TransactionInfo {
@Nullable
// 事务管理器
private final PlatformTransactionManager transactionManager;
@Nullable
// 事务属性
private final TransactionAttribute transactionAttribute;
// 连接点统一标识
private final String joinpointIdentification;
@Nullable
// 事务状态
private TransactionStatus transactionStatus;
@Nullable
// 历史事务信息
private TransactionInfo oldTransactionInfo;
private void bindToThread() {
// 公开当前TransactionStatus,保存任何现有的TransactionStatus,以便在此事务完成后恢复。
// 注意:将当前的TransactionInfo,置为old,然后加入新的TransactionInfo
// 这里的transactionInfoHolder是一个父类中的ThreadLocal变量,它记录当前线程所绑定的TrasactionInfo
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
}
TransactionIofo完全是一个记录对象,它完全将获取的TransactionStatus、TransactionAttribute和PlatformTransactionManager记录起来。
我们注目bindToThread()方法,TransactionInfo是一个内部类,而这个transactionInfoHolder是在它的外部类中声明的,且是一个ThreadLocal类型的线程级变量。他的逻辑是先从该transactionInfoHolder中取出该线程中当前记录的TransactionInfo,将其设置为当前TransactionInfo对象的oldTransactionInfo属性,然后将这个新的TransactionInfo设置进transactionInfoHolder中,当该事务结束,会再从oldTransactionInfo中回复旧的TransactionInfo~~
额外解释一下restoreThreadLocalStatus()方法,当事务方法调用结束,会调用cleanupTransactionInfo()清理当前线程的事务信息,我们理解了bindToThread,那么现在理解restoreThreadLocalStatus()就简单了,它就是将oldTransactionInfo取出,设置进transactionInfoHolder这个ThreadLocala类型的缓存中,实现了旧事务的恢复~~
事务方法处理完,释放掉TransactionInfo后,就要进行事务提交了:
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());
}
}
最终的提交任务,委托到了PlatformTransactionManager的实现上了:
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final void commit(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;
// 如果当前事务由于异常而设置了需要局部回滚,则进行回滚
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;
}
// 执行事务提交命令
processCommit(defStatus);
}
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
// 标记before completion事件师傅触发完成
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
// 准备事务提交相关的操作,这里只是一个hook方法,用于供给子类进行事务的自定义
prepareForCommit(status);
// 触发before commit事件
triggerBeforeCommit(status);
// 触发before completion事件
triggerBeforeCompletion(status);
// 标识before completion事件是否调用过
beforeCompletionInvoked = true;
// 如果当前事务是一个保存点事务,则释放当前的保存点,以使外层事务继续执行
// 保存点是为了解决PROPAGATION_NESTED传播机制的
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();
}
// 通过抛出异常的方式进行回滚
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been"
+ " marked as rollback-only");
}
} catch (UnexpectedRollbackException ex) {
// 在抛出异常时触发after completion事件
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
} catch (TransactionException ex) {
// 判断如果需要在commit失败时进行回滚,则进行回滚,否则触发after completion事件
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
} else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
} catch (RuntimeException | Error ex) {
// 如果before completion事件没有触发,则对其进行再次触发
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
try {
// 触发after commit事件
triggerAfterCommit(status);
} finally {
// 触发after completion事件
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
} finally {
// 清理当前线程中保存的事务状态信息
cleanupAfterCompletion(status);
}
}
那么保存点到底是如何出现的??Spring又是如何实现事务传播机制的呢??
这都要从handleExistingTransaction()说起,即当前线程存在事务,而又调用了一个其他方法时,Spring的处理逻辑代码:
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 如果当前被调用方法的事务传播机制是PROPAGATION_NEVER,那么抛出异常,因为PROPAGATION_NEVER表示
// 不能由事务方法调用
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 而如果当前被调用方法的传播机制是PROPAGATION_NOT_SUPPORTED,那么表示该方法
// 不需要在事务中运行,故挂起调用者方法的事务,然后以非事务的形式执行被调用的方法
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 暂停既有的事务
Object suspendedResources = suspend(transaction);
// 创建一个DefaultTransactionStatus,并返回。
// DefaultTransactionStatusz中有一个suspendedResources属性,存储的就是暂停的事务
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 如果被调用的方法的事务传播机制是PROPAGATION_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 {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建新的事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 配置事务,并绑定到线程上
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 如果被调用的方法的事务传播机制是PROPAGATION_NESTED,即嵌入式,那么:
// 1.如果支持事务嵌套,则创建一个新的书屋并设置保存点
// 2.如果不支持事务嵌套,那么就创建一个事务,并设置,注册到线程上,与PROPAGATION_REQUIRES_NEW类似
// 注意,这里并没有暂停外围的内务哟
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.
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
// 走到这里,基本就是 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);
}
Spring支持多种事务传播机制:
- PROPAGATION_SUPPORTS:如果当前线程内存在事务,那么就用该事务,如果没有,那么就以无事务的方式运行
- PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前线程存在事务,那么将其挂起。
- PROPAGATION_NEVER:以非事务方式运行,如果当前线程存在事务,那么异常
- PROPAGATION_REQUIRED:如果当前线程存在事务,那么加入到该事务中,如果当前线程不存在事务,那创建一个事务
- PROPAGATION_REQUIRES_NEW:必须在一个新的事务中。如果当前线程已经存在事务,那么挂起它
- PROPAGATION_MANDATORY:线程中必须存在事务,即必须被事务方法调用,否则抛出异常
- PROPAGATION_NESTED:理解Nested的关键是保存点【savepoint】。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW会另起一个事务,将会与他的父事务相互独立,而Nested的事务是依赖于他的父事务,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。但是Nested事务回滚,父事务可以通过其他手段【try-catch】,最终保证业务正常并提交。
在handleExistingTransaction方法中,Spring通过多个If条件判断,保证所有的传播机制可以生效,下面概述一下该方法的逻辑:
- 如果被调用的方法的事务传播机制为PROPAGATION_NEVER,那么根据语义,由于当前线程存在事务的,故抛出异常
- 如果被调用的方法的事务传播机制为PROPAGATION_NOT_SUPPORTED,那么根据语义,当前线程存在事务的,故需要先将其挂起,然后通过prepareTransactionStatus(…)方法创建一个无事务的TransactionStatus对象,并返回,最终代码自然以非事务执行了。
- 如果被调用的方法的事务传播机制为PROPAGATION_REQUIRES_NEW,那么根据语义,当前线程是存在事务的,故需要先将其挂起,然后创建一个新的事务,该新事务中保存了既有且挂起的事务,即suspendedResources,并将newTransaction属性设置为true,表示该事务是新的。接着,调用doBegin,该方法会重新为该事务获取数据库连接,因为父事务已经被挂起了,数据库连接自然也不能用。取消自动提交,并将新的数据库连接ConnectionHolder绑定到线程上,通过TransactionSynchronizationManager来实现的绑定的。到此,新的事务已经完毕,剩下的就是设置当前线程中事务的信息,其实也是配置TransactionSynchronizationManager。
- 如果被调用的方法的事务传播机制为PROPAGATION_NESTED,那么首先校验是否支持事务内嵌,因为JTA不支持事务内嵌,我们只关心支持的情况。在支持事务内嵌的情况下,Spring依托现有的父事务,通过prepareTransactionStatus(…)方法创建了一个TransactionStatus对象,设置newTransaction为false,表示会参与到父事务中,并设置newSynchronization为false,表示不会刷新当前线程的事务信息,然后创建保存点【savepoint】,通过由TransactionStatus实现的SavepointManager API来实现,并最终返回事务对象。
- 最后剩下了PROPAGATION_SUPPORTS、PROPAGATION_REQUIRED和PROPAGATION_MANDATORY,他们的处理逻辑是一样的,因为此时肯定有父事务,所以直接依托父事务即可,代码也是通过prepareTransactionStatus(…)方法创建的TransactionStatus,设置newTransaction为false,表示会参与到父事务中。
补漏,completeTransactionAfterThrowing,事务回滚
事务的回滚,是由TransactionManager负责的
一旦到回滚罗比,必然存一个异常对象,首先委托解析出的TransactionAttribute,判断你是否可以为该异常做回滚,我们前面也讲过,这里的实现其实就是RuleBasedTransactionAttribute,通过rollbackOn方法,如果判断为true,则回滚,否则就抛出异常
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;
}
}
}
}
注册BeanFactoryTransactionAttributeSourceAdvisor
该BeanFactoryTransactionAttributeSourceAdvisor是一个Advisor对象,当切面在为事务方法编织时,会讲Advisor.class的BeanDefintion找出来,并最终成为拦截器链的一员。
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);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
这是代码的截取片段,在这里,通过adviceBeanName,将TransactionInterceptor设置进来了,通过transactionAttributeSource,又将AnnotationTransactionAttributeSource设置进来了,因此可以说:BeanFactoryTransactionAttributeSourceAdvisor汇聚了TransactionInterceptor这个Advice,也囊括了AnnotationTransactionAttributeSource。