大家好,这篇文章将带领大家深入了解 Spring 事务实现机制。
在开始之前,我们需要注意区分 Spring 中物理事务和逻辑事务的区别:
- 物理事务:对应数据库实际执行的事务操作。物理事务需要通过 JDBC connection 开启、提交/回滚;
- 逻辑事务:从业务逻辑角度划分的事务单元。根据业务的需求,将一组 SQL 看成一个整体。在 Spring 中,一个事务单元可以理解成一个带有
@Transactional
的方法;
试想一下,如果有多个“逻辑事务”相互嵌套,该如何处理呢?是共用一个“物理事务”,还是单独再开启一个事务,又或者是其他操作?
这就是 Spring 事务传播行为所决定的事情,简单来说,Spring 事务传播行为就是用来解决多个逻辑事务 和 物理事务之间的对应关系问题的,除此之外,Spring 还提供了诸如事务扩展、声明式事务等这些简易的使用方式。
1. Spring 事务抽象
1.1. 核心组件简介
Spring 事务涉及到的核心组件:
- PlatformTransactionManager接口: Spring 事务管理的核心接口,定义了事务获取、提交、回滚三个最基础能力;
- TransactionDefinition 接口:用于定义事务(隔离级别、传播行为、超时、只读、回滚规则);
- TransactionStatus 接口:表示事务的状态,存储事务状态信息;
1.2. PlatformTransactionManager —— 事务管理器
Spring 通过事务管理器(PlatformTransactionManager)管理事务,接口定义如下:
public interface PlatformTransactionManager extends TransactionManager {
// 获取事务,会根据事务传播行为返回"事务状态"
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
// 提交事务
void commit(TransactionStatus status) throws TransactionException;
// 回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
这是一个策略接口,不同的平台可以有不同的实现,比如 JDBC 的实现为 DataSourceTransactionManager、Hibernate 中的实现为 HibernateTransactionManager、JPA 的实现为 JpaTransactionManager、Reidisson 的实现为 RedissonTransactionManager 等等;
Spring 提供了一个基础实现类 AbstractPlatformTransactionManager,这是一个模板类,封装了事务标准工作流程, 具体细节由子类实现;DataSourceTransactionManager、HibernateTransactionManager、JpaTransactionManager 等都继承了此抽象类;
1.3. TransactionDefinition —— 事务定义
根据上一节的内容,PlatformTransactionManager#getTransaction(...)
方法用于开启事务,并返回事务状态;其入参为TransactionDefinition
实例,用于描述一个事务,接口定义如下:
public interface TransactionDefinition {
// 事务传播行为常量
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
// 事务隔离级别常量
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1; // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
int ISOLATION_READ_COMMITTED = 2; // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
int ISOLATION_REPEATABLE_READ = 4; // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
int ISOLATION_SERIALIZABLE = 8; // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;
int TIMEOUT_DEFAULT = -1;
default int getPropagationBehavior() {
return PROPAGATION_REQUIRED;
}
default int getIsolationLevel() {
return ISOLATION_DEFAULT;
}
default int getTimeout() {
return TIMEOUT_DEFAULT;
}
default boolean isReadOnly() {
return false;
}
@Nullable
default String getName() {
return null;
}
// 获取默认事务定义
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
}
}
接口中定义了一些常量和 getter 方法,用于获取事务属性:传播行为、隔离级别、超时时间、是否只读、事务名称;
1.4. TransactionStatus —— 事务状态
TransactionStatus 表示一个事务的状态,可以用来获取事务信息、手动回滚事务(不用抛异常);继承自TransactionExecution 和 SavepointManager 接口,接口定义如下:
public interface TransactionExecution {
// 是否是新事务
boolean isNewTransaction();
// 设置事务为"只能回滚"状态, 即手动回滚事务
void setRollbackOnly();
boolean isRollbackOnly();
// 事务是否已完成
boolean isCompleted();
}
// Savepoint相关操作,目前工作中没用到过
public interface SavepointManager {
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
}
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
// 事务有没有Savapoint (JDBC才有,似乎不常用? 反正我没用到过)
boolean hasSavepoint();
@Override
void flush();
}
总结一句话:TransactionStatus 封装了一个事务的具体信息,可以用来手动回滚事务。
如果你用过 TransactionTemplate 编程式事务:
transactionTemplate.execute(status -> {xxxxxx});
这里的status
就是 TransactionStatus。
2. Spring 事务核心流程
Spring 事务通过模板方法模式定义了事务的工作流程,具体的事务管理器实现类只需要实现相关回调方法即可接入 Spring 事务。
2.1. 获取 / 开启事务——getTransaction(...)
在抽象类AbstractPlatformTransactionManager 中,getTransaction
是个一个模板方法,定义了标准的事务工作流程:
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
// ...
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// 1. 模板方法,获取当前事务对象(Object类型,因为子类实现各不相同)
Object transaction = doGetTransaction();
if (isExistingTransaction(transaction)) {
// 2. 当前线程已经存在事务,按照事务传播行为处理
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 3. 当前线程不存在事务
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
// 3.1 传播行为MANDATORY,当前线程不存在事务的情况下抛出异常
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
try {
// 3.2 开启事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// 3.3 不使用事务
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
}
doGetTransaction(...)
返回的是一个事务对象,内部封装了数据库连接等信息,其返回类型为什么是 Object?
- 事务对象在子类中的实现是不同的,父类不需要实际操作这个对象,用 Object 类型接收单纯起到一个引用的作用;
- 父类在调用
doBegin(...)
doRollBack(...)
doResume(...)
doSuspend(...)
doCleanupAfterCompletion(...)
这些模板方法时,会将doGetTransaction(...)
返回的transaction
实例再次传给子类,子类根据自己的具体实现进行强转;
getTransaction
整体流程是比较容易理解的,先获取当前线程事务信息,根据当前线程是否存在事务,产生 2 个分支逻辑:
- case 1: 当前线程存在事务,按照用户指定的事务传播行为进行处理,返回事务状态;
- case 2: 当前线程不存在事务,按照事务传播行为决定是否开始事务;
- case 2.1.
MANDATORY
:抛异常;(不常用) - case 2.2.
REQUIRED
、REQUIRES_NEW
、NESTED
:开启新事务; - case 2.3. 其余情况,不使用事务;(不常用)
- case 2.1.
先来介绍一下比较简单的 case 2.2 开启新事务,这个逻辑比较简单,只需调用子类doBegin
新创建一个事务实例,将事务信息封装进 TransactionStatus:
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 1. 实例化"事务状态",封装事务相关参数
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 2. 调用模板方法,开启事务
doBegin(transaction, definition);
// 3. 将事务信息绑定到当前线程 ThradLocal
prepareSynchronization(status, definition);
// 4. 返回事务状态
return status;
}
说明: TransactionStatus 封装了当前事务的状态信息,如数据库连接、是否新事务、是否开启事务同步、挂起的事务资源等。
回到 case 1 当前线程存在事务,这种情况有些麻烦了,Spring 会按照当前事务单元的事务传播行为进行处理,先来简单回顾下 Spring 事务传播行为:
REQUIRED
:如果存在一个事务,则加入当前事务;否则新创建一个事务;SUPPORTS
:如果存在一个事务,则加入当前事务;否则按照非事务的方式执行;MANDATORY
:如果存在一个事务,则加入当前事务;否则抛出异常;REQUIRES_NEW
:总是创建一个新的事务;如果已经存在一个事务,则将其挂起;NOT_SUPPORTED
:不支持事务;如果存在一个事务,则挂起此事务,自己以非事务的方式执行;NEVER
:永远不支持事务;如果存在一个事务,则抛出异常;NESTED
:如果存在事务,则运行在一个嵌套的事务中;如果没有活动的事务则按照REQUIRED
执行;
相关源码如下,按照 TransactionDefinition 中的传播行为分别处理:
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) {
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 传播行为=REQUIRES_NEW -> 挂起当前事务,开启新的事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 传播行为=NESTED -> 当前事务平台是否支持savepoint,支持则使用savepoint
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 (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 {
// 不使用savepoint,直接开启新事物
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// 传播行为=PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED
if (isValidateExistingTransaction()) { // 是否校验现存事务和此事务
// 校验两个事务定义是否兼容
// 略...
}
//PROPAGATION_SUPPORTS、 PROPAGATION_REQUIRED 都是加入当前事务,所以新创建一个事务状态即可
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
2.1.1. 事务挂起(suspend)与恢复(resume)
事务挂起(suspend) 和恢复(resume) 用于处理事务嵌套的问题。
举个例子:在一个事务中,当子方法需要执行独立事务时,就会将当前事务挂起,从TransactionSynchronizationManager
中暂时移除当前事务的状态,将当前事务状态封装进SuspendedResourcesHolder
,放入新事务的 TransactionStatus
中;子方法独立事务执行完毕之后,再拿出挂起的事务,重新绑定至TransactionSynchronizationManager
。
简言之,事务挂起就是将线程 ThreadLocal 中的事务状态暂时清空;而 resume 则是将事务状态恢复,重新设置到 ThreadLocal 中。
挂起 (suspend) 操作源码如下:
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);
// 把当前事务的各种状态封装进 SuspendedResourcesHolder
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;
}
}
恢复 (resume) 操作是挂起的逆操作,源码如下:
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
throws TransactionException {
if (resourcesHolder != null) {
// 1. 获取被挂起的资源
Object suspendedResources = resourcesHolder.suspendedResources;
if (suspendedResources != null) {
// 2. 调用子类恢复方法(子类一般是恢复数据库连接信息)
doResume(transaction, suspendedResources);
}
// 3. 恢复事务状态,将事务属性重新绑定至当前线程
List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
if (suspendedSynchronizations != null) {
TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
doResumeSynchronization(suspendedSynchronizations);
}
}
}
以上,便是 Spring 获取事务的大体流程。可以发现,抽象类对事务传播行为处理逻辑进行了封装,子类无需再去关心如何处理事务传播,只需实现父类给出的模板方法即可(doGetTransaction()
、doBegin(...)
等),父类会在合适的时机对子类方法进行调用,这就是模板方法模式的精髓所在。
2.2. 回滚事务 —— rollback
因为在 commit
的逻辑中涉及到了回滚,所以先来看看事务回滚的逻辑:
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
// ...
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
processRollback(defStatus, false);
}
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
// true-回滚完抛异常 false-不抛异常
boolean unexpectedRollback = unexpected;
try {
// 1. 触发TransactionSynchronization#beforeCompletion回调
triggerBeforeCompletion(status);
// 2.1 如果有savapoint,回滚到savepoint
if (status.hasSavepoint()) {
status.rollbackToHeldSavepoint();
}
// 2.2 如果是新事务 -> 调用模板方法 回滚事务
else if (status.isNewTransaction()) {
doRollback(status);
}
// 2.3 当前是子事务,只设置回滚状态,让外层事务回滚
else {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
doSetRollbackOnly(status); // 调用模板方法,设置"只能回滚"状态
}
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
// 3.1 异常情况下,触发afterCompletion回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 3.2 无异常情况下,触发afterCompletion回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
// 4. 清理事务状态,主要是清理跟线程绑定的状态
// 注:如果是子事务,会在这里恢复被挂起的事务
cleanupAfterCompletion(status);
}
}
// ...
}
processRollback
是按照“事务状态”进行回滚操作的:
- 如果有 savepoint,就回滚到上一个 savepoint(这个 case 应该不太常用,了解即可,反正我在工作中没用到过这个~);
- 如果是“新事务”,调用子类方法
doRollback
进行回滚;- “新事务”是啥意思?“嵌套事务”的最外层事务是新事务,内部事务不是新事务。比如, A 和 B 方法都有
@Transactional
注解,A 调用了 B,那么 A 中的status.isNewTransaction()
为 true,B 中的status.isNewTransaction()
为 false;
- “新事务”是啥意思?“嵌套事务”的最外层事务是新事务,内部事务不是新事务。比如, A 和 B 方法都有
- 如果不是“新事务”,即当前事务是“嵌套事务”的内部事务 status,此时设置“只能回滚状态”即可,让外层事务执行真正回滚操作;
2.3. 提交事务——commit
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;
// 1. 当前事务状态被设置了"只能回滚" -> 回滚事务
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus, false);
return;
}
// 2. defStatus.isGlobalRollbackOnly()为true 说明内层事务需要回滚,外层也要跟着回滚
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
processRollback(defStatus, true); // 这种情况下会抛出 UnexpectedRollbackException 异常
return;
}
// 3. 正常提交事务
processCommit(defStatus);
}
// ...
}
processCommit
的逻辑类似processRollback
,这里就不粘贴代码了。我们重点看一下commit
中的回滚逻辑:
- 第一种情况,如果当前 status 被设置了
rollbackOnly=true
,就执行回滚逻辑; - 第二种情况,稍有些复杂:
shouldCommitOnGlobalRollbackOnly
表示回滚的时候要不要执行 commit 逻辑,绝大部分情况都是 false,所以可以忽略这个条件;defStatus.isGlobalRollbackOnly()
为 true: 如果存在嵌套事务,内层事务通过status.setRollbackOnly()
方式回滚事务(没抛异常),此时外层事务也要跟着回滚;(不理解可以先看看 2.2 中status.isNewTransaction()=fasle
的情况)
3. Spring 声明式事务原理
Spring 声明式事务涉及到的组件如下:
- AnnotationTransactionAttributeSource:用于解析
@Transactional
注解中的属性; - TransactionInterceptor:事务切面逻辑;
- BeanFactoryTransactionAttributeSourceAdvisor:用于匹配
@Transactional
注解,为所在 bean 创建代理;
对于声明式事务,其基本原理是 AOP,具体切面逻辑如下:
public class TransactionInterceptor extends TransactionAspectSupport
implements MethodInterceptor, Serializable {
@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();
}
});
}
}
invokeWithinTransaction
方法的代码就不放了,其大致流程如下:
总结:声明式事务最终也是通过PlatformTransactionManager
进行事务管理的,只不过在此之前多了一步解析 @Transactional
注解的流程。
4. Spring 编程式事务原理
4.1. 基本用法
可以通过 TransactionTemplate 实现编程式事务,基本用法如下:
@Resource
private TransactionTemplate transactionTemplate;
public void testTransaction() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
// 执行业务代码
} catch (Exception e){
// 将事务设置为仅可回滚状态,可以用来代替抛异常触发回滚
status.setRollbackOnly();
}
}
});
}
4.2. 实现原理
编程式事务相对更加好理解一些,TransactionTemplate 相关源码如下:
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
@Nullable
private PlatformTransactionManager transactionManager;
// ...
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
// 1. 开启事务
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
// 2. 执行业务逻辑
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// 业务抛出异常,回滚
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// 业务抛出异常,回滚
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 无异常,提交事务
this.transactionManager.commit(status);
return result;
}
}
// ...
}
上述代码很容易理解,就是流水账式的代码:通过事务管理器开启事务、执行业务逻辑、提交或回滚事务;
5. 总结
本文首先介绍了 Spring 事务的核心组件:PlatformTransactionManager、TransactionDefinition 和TransactionStatus。
然后重点分析了事务管理器模板类 AbstractPlatformTransactionManager 中获取事务、回滚、提交事务的逻辑,Spring 在模板方法中已经帮我们处理了事务传播行为、嵌套事务等复杂的操作,具体的事务管理器只需实现模板类提供的回调方法即可接入 Spring 事务。
最后,我们简单的分析了一下 Spring 声明式事务和编程式事务的工作流程,它们都是依靠 Spring 的事务管理器PlatformTransactionManager
完成事务获取、提交或回滚的;