Spring事务源码详解

一. 简介

事务:

事务是逻辑上的一组操作,要么都执行,要么都不执行,关于事务的基本知识可以看我的这篇文章:事务的基础知识

Spring事务:

Spring 支持两种方式的事务管理:编程式事务管理声明式事务管理

  • 编程式事务管理:通过 TransactionTemplate或者TransactionManager手动管理事务,使用较少,但是可以让我们精准控制事务粒度,实现精确的细粒度事务控制
  • 声明式事务管理:通过 AOP 实现,@Transactional注解是最常用的声明式事务使用

二.通过例子来学习

maven依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>8.0.25</version>
 </dependency>
 <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
     <version>1.6.9</version>
 </dependency>

实体类:

public class Book {

    private int bookId;

    private String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    public Book() {
    }

    public int getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + '\'' +
                '}';
    }
}

Dao接口类:

import com.jingchuan.transaction.model.Book;

public interface LibraryDao {
	/**
	 * 取得书
	 * @param name
	 * @return book
	 */
	public Book getBook(String name);
	/**
	 * 增加书
     * @param book
	 */
	public void addBook(Book book);
	/**
	 * 删除书
     * @param name
	 */
	public void deleteBook(String name);
 
}

Dao实现类:

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

import com.jingchuan.transaction.model.Book;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class LibraryDaoImpl implements LibraryDao {

    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public Book getBook(String name) {
        String sql = "SELECT * FROM book WHERE bookname=?";
        Book mBook = (Book) jdbcTemplate.queryForObject(sql, new Object[]{name}, new RowMapper<Object>() {
            @Override
            public Object mapRow(ResultSet arg0, int arg1) throws SQLException {
                Book book = new Book();
                book.setBookId(arg0.getInt("bookId"));
                book.setBookName(arg0.getString("bookName"));
                return book;
            }
        });
        return mBook;
    }

    @Override
    public void addBook(Book book) {
        String sql = "INSERT INTO book VALUES(?,?)";
        jdbcTemplate.update(sql, book.getBookId(), book.getBookName());
//        jdbcTemplate.update(sql, book.getBookId(), book.getBookName());
    }

    @Override
    public void deleteBook(String name) {
        String sql = "DELETE FROM book WHERE bookname=?";
        jdbcTemplate.update(sql, name);
    }

}

transaction.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
       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
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!-- 配置数据源 -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--配置一个JdbcTemplate实例,并将这个“共享的”,“安全的”实例注入到不同的DAO类中去 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 声明事务管理器 -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 需要实施事务增强的目标业务Bean -->
    <bean id="libraryFactory" class="com.jingchuan.transaction.dao.LibraryDaoImpl"
          p:jdbcTemplate-ref="jdbcTemplate" />

    <!-- 使用tx/aop来配置 -->
    <aop:config>
        <!-- 通过aop定义事务增强切面 -->
        <aop:pointcut id="serviceMethod"
                      expression="execution(* com.jingchuan.transaction.dao.LibraryDaoImpl.*(..))" />
        <!-- 引用事务增强 -->
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>

    <!--事务增强 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- 事务属性定义 -->
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="add*" rollback-for="Exception" propagation="REQUIRED"/>
            <tx:method name="del*" />
        </tx:attributes>
    </tx:advice>
</beans>

测试类:

import com.jingchuan.transaction.dao.LibraryDao;
import com.jingchuan.transaction.model.Book;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestTransaction {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:transaction.xml");
        Book book1 = new Book(1, "西游记");
        Book book2 = new Book(2, "红楼梦");
        Book book3 = new Book(3, "金瓶梅");
        Book book4 = new Book(4, "三国演义");
        Book book5 = new Book(5, "水浒传");
        LibraryDao libraryDaoImpl = (LibraryDao) ctx.getBean("libraryFactory");
        libraryDaoImpl.addBook(book2);
        System.out.println(libraryDaoImpl.getBook("西游记"));
    }

}

需要自己创建一个数据库并创建Book表,bookId和bookName两个字段:

CREATE TABLE `book` (
  `bookId` int(11) NOT NULL,
  `bookName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`bookId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

三. 跟着例子看源码

3.1 Spring加载事务相关Bean并通过代理调用事务代码过程

根据IOCAOP的知识,应该了解到上面的例子中,transaction.xml中的每个标签都会被加载成一个个Bean定义和Bean实例存储在spring工厂和容器中,对于xml配置中的前面部分的标签这里就不再一一跟进了,不了解的同学可以去看我之前的IOC源码详解AOP源码分析,我们直接来到tx:advice标签的解析org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	if (delegate.isDefaultNamespace(root)) {
		NodeList nl = root.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if (delegate.isDefaultNamespace(ele)) {
					parseDefaultElement(ele, delegate);
				}
				else {
					//自定义标签解析  我们的tx:advice标签就是事务自定义标签
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}

根据自定义标签解析的过程,我们看:

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	// 这个namespaceUri 在tx标签解析时值为:http://www.springframework.org/schema/tx
	// 因为xml配置中顶部beans xmlns配置了tx标签的解析规范
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	// 根据namespaceUri 匹配他的标签处理器
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	// 根据匹配到的处理器进行标签解析
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

在上面这段代码中,this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);这一步就是根据namespaceUri的值去找到它对应的处理类,spring-tx包在META-INF\spring.handlers中配置了

http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

所以在resolve(namespaceUri)这一步会调用org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve,然后实例化org.springframework.transaction.config.TxNamespaceHandler并调用他的init方法,这个就不贴源代码了,这一步不复杂,我们看TxNamespaceHandlerinit方法:

public void init() {
	registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
	registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
	registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

可以看到这个init方法里面定义了tx标签下的每个子标签名称对应的解析器,后续事务相关的配置就根据这个定义进行解析的。这个和aop的其实是同一个套路。
然后回到:org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)方法,看最后一步,根据拿到的TxNamespaceHandler调用其parse方法,这一步会先调用父类的org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse方法,根据配置,我们第一个解析的是tx:advice标签,所以这里就是获取advice标签的解析器,也就是上面init方法中定义的TxAdviceBeanDefinitionParser类,所以这个parse最终会来到TxAdviceBeanDefinitionParser的父类AbstractBeanDefinitionParserparse方法,这个方法内部的解析逻辑这里就不一一跟进了,最终就是把我们配置里面的内容解析成BeanDefinition,这个BeanDefinition实际是TransactionInterceptor的定义,他的Bean name是txAdvice

然后略过其他的步骤来到org.springframework.context.support.AbstractApplicationContext#refresh方法的finishBeanFactoryInitialization(beanFactory);
这一步是实例化所有单例Bean,当实例化我们xml配置中的libraryFactory时,发现他符合我们AOP代理的配置规则,所以会给他创建代理对象,那么这个代理对象的的目标对象就是LibraryDaoImpl,切入点(pointcut)就是配置中的com.jingchuan.transaction.dao.LibraryDaoImpl.*(..),他的通知行为(advice)就是org.springframework.transaction.interceptor.TransactionInterceptor,然后JdkDynamicAopProxy根据这些创建代理类并放入Spring容器中。关于AOP拦截Bean创建并创建代理的过程,大家自行了解AOP源码

那么至此,Spring加载配置文件中的Bean定义和根据定义创建实例就算完成了。

然后来到测试类中调用libraryDaoImpl.addBook(book2),那么我们上面分析过了,libraryDaoImpl这个实例其实是JdkDynamicAopProxy创建的代理类代理的,所以会进入org.springframework.aop.framework.JdkDynamicAopProxy#invoke反射执行目标代码,经过代理类处理反射会来到:org.springframework.transaction.interceptor.TransactionInterceptor#invoke方法

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);

	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	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();
		}
	});
}

这里就是真正进入Spring事务的代码了

3.2 分析事务源码

上面我们知道进入了org.springframework.transaction.interceptor.TransactionInterceptor#invoke方法,所以我们直接进入看org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

	// If the transaction attribute is null, the method is non-transactional.
	// 获取事务属性
	TransactionAttributeSource tas = getTransactionAttributeSource();
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	// 根据事务属性信息获取事务管理器 这里我们配置的是DataSourceTransactionManager
	final TransactionManager tm = determineTransactionManager(txAttr);
	// 判断是不是 响应式/反应式 事务
	if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
		boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
		boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
				COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
		if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
			throw new IllegalStateException("Coroutines invocation not supported: " + method);
		}
		CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);

		ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
			Class<?> reactiveType =
					(isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
			ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
			if (adapter == null) {
				throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
						method.getReturnType());
			}
			return new ReactiveTransactionSupport(adapter);
		});

		InvocationCallback callback = invocation;
		if (corInv != null) {
			callback = () -> CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
		}
		Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager) tm);
		if (corInv != null) {
			Publisher<?> pr = (Publisher<?>) result;
			return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow(pr) :
					KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation()));
		}
		return result;
	}

	PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
	// 获取目标方法唯一标识   在我们例子中是:com.jingchuan.transaction.dao.LibraryDaoImpl.addBook
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	
	//判断是不是声明式事务
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
		// 如果需要那就创建事务获取TransactionInfo 
		TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

		Object retVal;
		try {
			// This is an around advice: Invoke the next interceptor in the chain.
			// This will normally result in a target object being invoked.
			// 调用真实的目标方法  也就是我们的addBook方法
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// target invocation exception
			// 如果发生异常,那么处理异常之后的逻辑
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			// 清理事务  
			cleanupTransactionInfo(txInfo);
		}

		if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
			// Set rollback-only in case of Vavr failure matching our rollback rules...
			TransactionStatus status = txInfo.getTransactionStatus();
			if (status != null && txAttr != null) {
				retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
			}
		}
		// 提交事务  这个只有在没发生异常的时候才会执行到这里  发生异常的时候就throw了
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}
	//编程式事务
	else {
		Object result;
		final ThrowableHolder throwableHolder = new ThrowableHolder();

		// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
		try {
			result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
				TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
				try {
					Object retVal = invocation.proceedWithInvocation();
					if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
						// Set rollback-only in case of Vavr failure matching our rollback rules...
						retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
					}
					return retVal;
				}
				catch (Throwable ex) {
					if (txAttr.rollbackOn(ex)) {
						// A RuntimeException: will lead to a rollback.
						if (ex instanceof RuntimeException) {
							throw (RuntimeException) ex;
						}
						else {
							throw new ThrowableHolderException(ex);
						}
					}
					else {
						// A normal return value: will lead to a commit.
						throwableHolder.throwable = ex;
						return null;
					}
				}
				finally {
					// 执行完成后从ThreadLocal中去掉本次的事务信息
					cleanupTransactionInfo(txInfo);
				}
			});
		}
		catch (ThrowableHolderException ex) {
			throw ex.getCause();
		}
		catch (TransactionSystemException ex2) {
			if (throwableHolder.throwable != null) {
				logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
				ex2.initApplicationException(throwableHolder.throwable);
			}
			throw ex2;
		}
		catch (Throwable ex2) {
			if (throwableHolder.throwable != null) {
				logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
			}
			throw ex2;
		}

		// Check result state: It might indicate a Throwable to rethrow.
		if (throwableHolder.throwable != null) {
			throw throwableHolder.throwable;
		}
		return result;
	}
}

上面这个方法就是真正的事务处理逻辑了,我们主要来看声明式事务的处理逻辑,分开来看

  1. createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
  2. completeTransactionAfterThrowing(txInfo, ex);
  3. commitTransactionAfterReturning(txInfo);

3.2.1 先看createTransactionIfNecessary方法

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

	// If no name specified, apply method identification as transaction name.
	if (txAttr != null && txAttr.getName() == null) {
		txAttr = new DelegatingTransactionAttribute(txAttr) {
			@Override
			public String getName() {
				return joinpointIdentification;
			}
		};
	}

	TransactionStatus status = null;
	if (txAttr != null) {
		if (tm != null) {
			// 获取事务 根据不同事务传播行为决定事务创建
			status = tm.getTransaction(txAttr);
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
						"] because no transaction manager has been configured");
			}
		}
	}
	// 把获取的事务包装成TransactionInfo并绑定到ThreadLocal
	return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

进入tm.getTransaction(txAttr);看源码

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

	// Use defaults if no transaction definition given.
	TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
	// doGet开头的方法 肯定就是创建并返回事务了
	Object transaction = doGetTransaction();
	boolean debugEnabled = logger.isDebugEnabled();

	// 判断上面transaction 是不是已有的事务
	if (isExistingTransaction(transaction)) {
		// Existing transaction found -> check propagation behavior to find out how to behave.
		// 根据已有事物的传播行为进行对应处理
		return handleExistingTransaction(def, transaction, debugEnabled);
	}
	
	// 能走到这里说明就不存在已有的事务 往下的处理逻辑就是针对没有已创建事务的处理
	
	// Check definition settings for new transaction.
	// 检查事务的超时时间是否设置正确
	if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
		throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
	}

	// No existing transaction found -> check propagation behavior to find out how to proceed.
	// 如果事务定义为MANDATORY,那这时候必须在一个已有事务里面运行,走到这里说明没有已有的事务,就会报错
	if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		throw new IllegalTransactionStateException(
				"No existing transaction found for transaction marked with propagation 'mandatory'");
	}
	// 如果事务定义为REQUIRED或者REQUIRES_NEW或者NESTED
	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 {
			// 开启一个事务
			return startTransaction(def, transaction, debugEnabled, suspendedResources);
		}
		catch (RuntimeException | Error ex) {
			resume(null, suspendedResources);
			throw ex;
		}
	}
	else {
		// Create "empty" transaction: no actual transaction, but potentially synchronization.
		if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
			logger.warn("Custom isolation level specified but no actual transaction initiated; " +
					"isolation level will effectively be ignored: " + def);
		}
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
		return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
	}
}

上面这个方法中,我们重点看三个方法:

  1. doGetTransaction()
  2. handleExistingTransaction(def, transaction, debugEnabled)
  3. startTransaction(def, transaction, debugEnabled, suspendedResources)
3.2.1.1 首先来看doGetTransaction()

因为我们例子中使用的是DataSourceTransactionManager,所以自然会调用到org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction

protected Object doGetTransaction() {
	// 创建一个DataSourceTransactionObject
	DataSourceTransactionObject txObject = new DataSourceTransactionObject();
	// 设置本次事务中是否允许保存点, isNestedTransactionAllowed() 为true
	txObject.setSavepointAllowed(isNestedTransactionAllowed());
	// 这里是根据数据库链接属性去当前线程中获取缓存,如果当前线程中不存在,那么就返回null
	ConnectionHolder conHolder =
			(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
	txObject.setConnectionHolder(conHolder, false);
	return txObject;
}

最终返回一个DataSourceTransactionObject 再回到org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction继续跟进

3.2.1.2 分析handleExistingTransaction(def, transaction, debugEnabled)方法

根据上面的分析我们知道这个方法是处理在当前线程中已存在事务时的处理流程

private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
	// 如果是事务定义是NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
		throw new IllegalTransactionStateException(
				"Existing transaction found for transaction marked with propagation 'never'");
	}
	// 如果当前事务定义是NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
		if (debugEnabled) {
			logger.debug("Suspending current transaction");
		}
		// 挂起当前事务
		Object suspendedResources = suspend(transaction);
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
		// 创建新的TransactionStatus
		return prepareTransactionStatus(
				definition, null, false, newSynchronization, debugEnabled, suspendedResources);
	}
	// 如果当前事务定义为REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
		if (debugEnabled) {
			logger.debug("Suspending current transaction, creating new transaction with name [" +
					definition.getName() + "]");
		}
		// 挂起当前事务
		SuspendedResourcesHolder suspendedResources = suspend(transaction);
		try {
			//开启新事务
			return startTransaction(definition, transaction, debugEnabled, suspendedResources);
		}
		catch (RuntimeException | Error beginEx) {
			resumeAfterBeginException(transaction, suspendedResources, beginEx);
			throw beginEx;
		}
	}

	// 如果当前事务定义为NESTED  如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作,这个是事务的嵌套
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
		// 是否允许嵌套事务  不允许的话直接抛出异常
		if (!isNestedTransactionAllowed()) {
			throw new NestedTransactionNotSupportedException(
					"Transaction manager does not allow nested transactions by default - " +
					"specify 'nestedTransactionAllowed' property with value 'true'");
		}
		if (debugEnabled) {
			logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
		}
		// 是否为嵌套事务使用保存点
		if (useSavepointForNestedTransaction()) {
			// Create savepoint within existing Spring-managed transaction,
			// through the SavepointManager API implemented by TransactionStatus.
			// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
			DefaultTransactionStatus status =
					prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
			status.createAndHoldSavepoint();
			return status;
		}
		else {
			// Nested transaction through nested begin and commit/rollback calls.
			// Usually only for JTA: Spring synchronization might get activated here
			// in case of a pre-existing JTA transaction.
			// 开启新事务
			return startTransaction(definition, transaction, debugEnabled, null);
		}
	}

	// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
	if (debugEnabled) {
		logger.debug("Participating in existing transaction");
	}
	if (isValidateExistingTransaction()) {
		if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
			Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
			if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
				Constants isoConstants = DefaultTransactionDefinition.constants;
				throw new IllegalTransactionStateException("Participating transaction with definition [" +
						definition + "] specifies isolation level which is incompatible with existing transaction: " +
						(currentIsolationLevel != null ?
								isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
								"(unknown)"));
			}
		}
		if (!definition.isReadOnly()) {
			if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
				throw new IllegalTransactionStateException("Participating transaction with definition [" +
						definition + "] is not marked as read-only but existing transaction is");
			}
		}
	}
	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
3.2.1.3 分析startTransaction(def, transaction, debugEnabled, suspendedResources)方法
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
	// 创建一个DefaultTransactionStatus 记录了事务的各种属性信息
	DefaultTransactionStatus status = newTransactionStatus(
			definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
	// 开启事务链接  如果是个新事务  那么绑定到当前线程
	doBegin(transaction, definition);
	//新同步事务的设置
	prepareSynchronization(status, definition);
	return status;
}

再看doBegin(transaction, definition);方法,因为我们使用DataSourceTransactionManager所以就到了org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

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());

		// 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).
		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()) {
			// 如果是个新事务,那么把这个事务已链接信息为key 事务链接为value 绑定到当前线程
			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);
	}
}

那到这里,事务创建的过程就分析完成了,然后我们回到org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction方法,我们刚才基本的过了一遍createTransactionIfNecessary(ptm, txAttr, joinpointIdentification)这一步,最终是根据我们当前的事务状态和传播行为等信息,得到了当前事务的TransactionInfo
然后接着就是反射执行目标方法,也就是我们例子中的addBook
执行完成后根据是否发生异常来处理后续流程,比如异常回滚或者没有异常的时候正常提交事务。

3.2.2 分析completeTransactionAfterThrowing(txInfo, ex)

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;
			}
		}
	}
}

其实上面这段代码就是根据我们的配置来处理发生异常的时候,需不需要回滚事务或者提交事务。

其中txInfo.transactionAttribute.rollbackOn(ex)这个就是用来判断是不是需要回滚的重要逻辑,他向下的实际调用链是:

  1. org.springframework.transaction.interceptor.DelegatingTransactionAttribute#rollbackOn 抽象类委托处理
  2. org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn 异常规则匹配具体实现
  3. org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn 如果规则匹配没有匹配到,那么走这个默认的

我们具体看第二步的规则匹配:

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;

	if (this.rollbackRules != null) {
		// 这个this.rollbackRules 就是我们配置的具体的异常
		// 比如@Transactional的rollbackFor和noRollbackFor 他们都是RollbackRuleAttribute
		// 只不过区分为RollbackRuleAttribute 和 NoRollbackRuleAttribute  也就是回滚的异常和不会滚的异常
		for (RollbackRuleAttribute rule : this.rollbackRules) {
			// 循环进行深度匹配   其实就是看异常是不是和配置的异常匹配 并从子类往上级的父类进行追踪 
			// 每次都是先匹配回滚的  再匹配不会滚的  同时从子类开始匹配(子类优先)
			int depth = rule.getDepth(ex);
			if (depth >= 0 && depth < deepest) {
				// 如果匹配到   那么就设置匹配成功的记录
				deepest = depth;
				winner = rule;
			}
		}
	}

	if (logger.isTraceEnabled()) {
		logger.trace("Winning rollback rule is: " + winner);
	}

	// User superclass behavior (rollback on unchecked) if no rule matches.
	if (winner == null) {
		// 如果没匹配到  那么使用默认的规则  也就是DefaultTransactionAttribute的rollbackOn
		logger.trace("No relevant rollback rule found: applying default rules");
		return super.rollbackOn(ex);
	}
	
	// 最后再看匹配到的是不是NoRollbackRuleAttribute(不需要回滚的)  如果是那么就不会滚
	return !(winner instanceof NoRollbackRuleAttribute);
}

上面这个方法就是具体看会不会回滚的重点,其中深度匹配的逻辑大家可以断点再详细看看。
然后如果我们平时使用的@Transactional注解 不写rollbackFor = Exception.class,那么他就只会捕捉到RuntimeException或者Error,因为在默认的DefaultTransactionAttribute匹配规则中是:

public boolean rollbackOn(Throwable ex) {
	return (ex instanceof RuntimeException || ex instanceof Error);
}

所以大家在使用@Transactional注解的时候要注意异常的时候是否可以回滚。同时配置了rollbackFornoRollbackFor属性的时候要注意匹配的规则是有优先级的,尤其是rollbackFornoRollbackFor的异常类有父子级关系的时候。 实再不确定的时候就在这里断点看一看

3.2.3 分析commitTransactionAfterReturning(txInfo)

目标方法正常执行完成后就会执行提交事务

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());
	}
}

txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());这里的commit会来到:org.springframework.transaction.support.AbstractPlatformTransactionManager#commit

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);
}

跟进到:org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
	try {
		boolean beforeCompletionInvoked = false;

		try {
			boolean unexpectedRollback = false;
			// 模板方法扩展
			prepareForCommit(status);
			// 提交前的各种扩展处理
			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 (UnexpectedRollbackException ex) {
			// can only be caused by doCommit
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
			throw ex;
		}
		catch (TransactionException ex) {
			// can only be caused by doCommit
			if (isRollbackOnCommitFailure()) {
				doRollbackOnCommitException(status, ex);
			}
			else {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			}
			throw ex;
		}
		catch (RuntimeException | Error ex) {
			if (!beforeCompletionInvoked) {
				triggerBeforeCompletion(status);
			}
			doRollbackOnCommitException(status, ex);
			throw ex;
		}

		// Trigger afterCommit callbacks, with an exception thrown there
		// propagated to callers but the transaction still considered as committed.
		try {
			// 处理提交后的 扩展/拦截 处理 
			triggerAfterCommit(status);
		}
		finally {
			// 提交之后 
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
		}

	}
	finally {
		// 清楚事务的各种本地线程数据  包括设置为自动提交等
		cleanupAfterCompletion(status);
	}
}

再看:doCommit(status);,因为我们使用的是DataSourceTransactionManager,所以会来到org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit

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事务基本流程分析了一遍,过程中有很多地方一笔带过了,大家自己跟着断点再细看吧,全部写的话太多了写不完,过程中有不正确的欢迎指正。

  • 10
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Spring事务Spring框架中非常重要的特性之一,它提供了对事务的管理和控制。在Spring中,事务源码主要涉及到以下几个方面: 1. 事务管理器接口(PlatformTransactionManager):该接口定义了事务管理器的基本操作,如开启事务、提交事务、回滚事务等。不同的数据访问技术(如JDBC、Hibernate、JPA等)有不同的实现类。 2. 事务定义接口(TransactionDefinition):该接口定义了事务的属性,如隔离级别、传播行为、超时时间等。Spring中提供了多种事务定义的实现类,例如DefaultTransactionDefinition。 3. 事务状态接口(TransactionStatus):该接口定义了事务的状态信息,如是否处于活动状态、是否可以提交、是否可以回滚等。Spring中提供了多种事务状态的实现类,例如DefaultTransactionStatus。 4. 事务切面(TransactionAspectSupport):该类是Spring事务的核心类之一,它是一个抽象类,提供了对事务的具体实现。它通过AOP技术为带有@Transactional注解的方法创建代理对象,并在方法执行前后进行事务的开启、提交和回滚等操作。 5. 事务切面的通知类(TransactionInterceptor):该类是Spring事务的通知类之一,实现了MethodInterceptor接口。它负责在方法执行前后执行事务相关的逻辑,如开启事务、提交事务、回滚事务等。 以上是Spring事务源码的主要组成部分,通过对这些类的深入理解和研究,可以更好地掌握Spring事务的原理和实现机制。注意,这里只是简单介绍了一些关键的类和接口,实际上Spring事务源码非常庞大且复杂。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值