Spring事务源码(一)
前言
本文讲述当前线程无事务时,是如何创建新事务的
Spring事务的传播特性:
- REQUIRED 如果当前线程无事务则创建事务,有事务则加入当前事务
- SUPPORTS 如果当前线程有事务则加入当前事务,如果无事务则不创建事务,以无事务方式执行
- MANDATORY 如果当前线程有事务则加入当前事务,如果无事务则抛出异常throw new IllegalTransactionStateException(
“No existing transaction found for transaction marked with propagation ‘mandatory’”); - REQUIRES_NEW 如果当前线程有事务则挂起当前事务,然后新建立一个事务,如果无事务则创建事务
- NOT_SUPPORTED 如果当前线程有事务则挂起当前事务,然后然后以无事务方式执行,如果无事务则以无事务方式执行
- NEVER 如果当前线程有事务则抛出异常throw new IllegalTransactionStateException(
“Existing transaction found for transaction marked with propagation ‘never’”); - NESTED 果当前线程无事务则创建事务,如果之前有事务,将作为之前事务的子事务,这个传播属性可以创建SavePoint(可以回滚的保存点)
一、ProxyTransactionManagementConfiguration
Spring事务配置的3个重要Bean:
- TransactionAttributeSource @Transactinal注解的解析类
- TransactionInterceptor Spring事务的处理类 也是Spring Aop中的advice,是Spring事务分析的重要类
- BeanFactoryTransactionAttributeSourceAdvisor Spring事务的advisor
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
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() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
二、BeanFactoryTransactionAttributeSourceAdvisor
声明类一个TransactionAttributeSourcePointcut当作这个advisor的切面,它去判断哪些类需要Spring事务去增强
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
// 在其matches方法上调用TransactionAttributeSource的getTransactionAttribute的方法
// 基本思路是TransactionAttributeSource类里创建里一个SpringTransactionAnnotationParser,通过它调用
// AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
element, Transactional.class);
// 将attributes包装成RuleBasedTransactionAttribute返回给此方法,如果不为空说明需要给目标类做代理
@Override
public boolean matches(Method method, Class<?> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
}
三、TransactionInterceptor
TransactionInterceptor实现了MthodInterceptor接口,代理对象执行相应的方法时会先执行MthodInterceptor的invoke方法(其中一段流程略过,如知道AOP原理将很好理解为什么会执行到invoke方法,本篇文章着重讲解事务功能,对AOP方面调用不去阐述)
@Override
public Object invoke(final 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);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
核心事务底层封装实现方法
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 通过TransactionAttributeSource解析方法上的@Transactional注解,如果方法上没有则解析类上的@Transactional注解,
// 把注解信息封装成TransactionAttribute
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 获取PlatformTransactionManager, 通常我们都是使用DataSourceTransactionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// DataSourceTransactionManager没有实现CallbackPreferringPlatformTransactionManager
// 所以走这一块代码
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 获取事务信息,并将事务信息封装成TransactionInfo
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// Spring Aop往下传递执行方法。直至执行原始方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 遇到异常需要如何处理事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 将txInfo存在旧的TransactionInfo,那么将旧的TransactionInfo放入线程变量transactionInfoHolder中
cleanupTransactionInfo(txInfo);
}
// 走到这里说明没有异常,准备提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
}
}
获取事务信息的方法
protected TransactionInfo createTransactionIfNecessary(
PlatformTransactionManager tm, 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;
if (txAttr != null) {
if (tm != null) {
//通过事务管理器获取事务状态对象TransactionStatus
status = tm.getTransaction(txAttr);
}
}
// 将status和事务管理器、事务属性封装成TransactionInfo事务信息对象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
核心方法获取事务状态
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
// 获取一个事务对象transaction,doGetTransaction源码如下
/*
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
从线程变量里取出ConnectionHolder填充到txObject,因为是从线程变量取出来的,所以标记不是一个新的holder
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
*/
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 判断事务对象事务已经包含事务,如果已存在事务,就按已有事务的方式执行方法
// isExistingTransaction源码如下:txObject的ConnectionHolder不为空且属于事务开始状态
// 则可以判断当前线程已经存在事务
/*
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
*/
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 如果走到这里说明当前线程无事务存在,但如果传播行为是PROPAGATION.MANDATORY(强制要求存在事务,否则抛出异常)
// 则抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 如果当前线程无事务,但传播行为如下3种则需要创建
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 因为此处无事务,所以不会挂起任务事务信息,如事务同步管理器有事务同步器,仅仅保存一些线程变量到SuspendedResourcesHolder
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
// 判断是否要开启事务同步器,默认都是要的
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// new一个status对象,把事务对象transaction,挂起的信息存进去,并标记为一个新事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 打开新事务
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
// 其他几种传播行为(SUPPORTS、NOT_SUPPORTED、NEVER)以无事务方式运行当前方法
// 判断是否要开启事务同步器,只有SYNCHRONIZATION_ALWAYS才开启事务同步器管理
// SYNCHRONIZATION_ON_ACTUAL_TRANSACTION适应于只有开启真实事务环境下
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
doBegin
打开新事务的原理:
- dataSource的connection如果在没事务的情况下,遇到增,删,改会自动开启事务。
- 如autoCommit设置为true,则每一个SQL修改完数据都执行完会自动执行事务commit
- 把autoCommit设置成false,事务的提交与回滚交与Spring事务来管理,即实现了一个事务内执行多个Sql。
- 因为connection和事务是关联的,所以持有connection,就可以当作持有当前事务,所以要把connection对象封装一下,存进线程变量中
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// transaction对象不持有Connection对象时判断当前线程无事务,通过dataSource获取一个Connection
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.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();
//设置当前Connection的隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
//记录Connection之前的隔离级别,用于执行完事务方便恢复Connection的隔离级别
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
// 设置autoCommit为false,即事务由Spring事务来管理
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 目前只有设置如果当前事务属性配置的是ReadOnly时,把当前事务编程ReadOnly
prepareTransactionalConnection(con, definition);
// 设置当时ConnectionHolder时开启事务的
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
// 如果ConnectionHolder是通过dataSource得到的,就是NewConnectionHolder
// 那么就把它放入线程变量中,方便在同一个线程里其他地方取出来判断当前线程是否有事务
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
}
总结
- 事务是和Connection绑定的,判断当前线程是否有事务就是取出线程变量ConnectionHolder
- 创建事务是通过事务管理器的dataSource获取Connection, 并封装成ConnectionHolder放入线程变量中
- 创建事务只有当前线程无事务且传播行为为REQUIRED,REQUIRES_NEW,NESTED才会取创建事务
- 创建事务完毕后调用prepareTransactionStatus初始化事务同步管理器initSynchronization,
并把事务名称,隔离级别放入线程变量中,方便用户注册事务同步器参与事务的生命周期方法。 - 事务创建成功后把事务信息对象DataSourceTransactionObject,是否新事务状态 封装成TransactionStatus