事务重入
事务重入的核心处理逻辑:
private TransactionStatus handleExistingTransaction( TransactionDefinition definition,
Object transaction, boolean debugEnabled){
// 传播行为是 PROPAGATION_NEVER,需要以非事务方式执行操作,如果当前事务存在则【抛出异常】
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException();
}
// 传播行为是 PROPAGATION_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);
}
// 开启新事物的逻辑
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
// 【挂起当前事务】
SuspendedResourcesHolder suspendedResources = suspend(transaction);
// 【开启新事物】
}
// 传播行为是 PROPAGATION_NESTED,嵌套事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// Spring 默认不支持内嵌事务
// 【开启方式】:<property name="nestedTransactionAllowed" value="true">
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException();
}
if (useSavepointForNestedTransaction()) {
// 为当前方法创建一个 TransactionStatus 对象,
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建一个 JDBC 的保存点
status.createAndHoldSavepoint();
// 不需要使用同步,直接返回
return status;
}
else {
// Usually only for JTA transaction,开启一个新事务
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED,【使用当前的事务】
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
挂起恢复
AbstractPlatformTransactionManager#suspend:挂起事务,并获得一个上下文信息对象
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) {
// 事务是同步状态的
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
// do it
suspendedResources = doSuspend(transaction);
}
//将上层事务绑定在线程上下文的变量全部取出来
//...
// 通过被挂起的资源和上层事务的上下文变量,创建一个【SuspendedResourcesHolder】返回
return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations,
name, readOnly, isolationLevel, wasActive);
} //...
}
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 将当前方法的事务对象 connectionHolder 属性置为 null,不和上层共享资源
// 当前方法有可能是不开启事务或者要开启一个独立的事务
txObject.setConnectionHolder(null);
// 【解绑在线程上的事务】
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
AbstractPlatformTransactionManager#resume:恢复现场,根据挂起资源去恢复线程上下文信息
protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder) {
if (resourcesHolder != null) {
// 获取被挂起的事务资源
Object suspendedResources = resourcesHolder.suspendedResources;
if (suspendedResources != null) {
//绑定上一个事务的 ConnectionHolder 到线程上下文
doResume(transaction, suspendedResources);
}
List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
if (suspendedSynchronizations != null) {
//....
// 将线程上下文变量恢复为上一个事务的挂起现场
doResumeSynchronization(suspendedSynchronizations);
}
}
}
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
// doSuspend 的逆动作,【绑定资源】
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
提交回滚
回滚方式
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
// 事务状态信息不为空进入逻辑
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 条件二成立 说明目标方法抛出的异常需要回滚事务
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 事务管理器的回滚方法
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {}
}
else {
// 执行到这里,说明当前事务虽然抛出了异常,但是该异常并不会导致整个事务回滚
try {
// 提交事务
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {}
}
}
}
public boolean rollbackOn(Throwable ex) {
// 继承自 RuntimeException 或 error 的是【非检查型异常】,才会归滚事务
// 如果配置了其他回滚错误,会获取到回滚规则 rollbackRules 进行判断
return (ex instanceof RuntimeException || ex instanceof Error);
}
public final void rollback(TransactionStatus status) throws TransactionException {
// 事务已经完成不需要回滚
if (status.isCompleted()) {
throw new IllegalTransactionStateException();
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 开始回滚事务
processRollback(defStatus, false);
}
AbstractPlatformTransactionManager#processRollback:事务回滚
-
triggerBeforeCompletion(status):用来做扩展逻辑,回滚前的前置处理 -
if (status.hasSavepoint()):条件成立说明当前事务是一个内嵌事务,当前方法只是复用了上层事务的一个内嵌事务status.rollbackToHeldSavepoint():内嵌事务加入事务时会创建一个保存点,此时恢复至保存点 -
if (status.isNewTransaction()):说明事务是当前连接开启的,需要去回滚事务doRollback(status):真正的的回滚函数DataSourceTransactionObject txObject = status.getTransaction():获取事务对象Connection con = txObject.getConnectionHolder().getConnection():获取连接对象con.rollback():JDBC 的方式回滚事务
-
else:当前方法是共享的上层的事务,和上层使用同一个 Conn 资源,共享的事务不能直接回滚,应该交给上层处理doSetRollbackOnly(status):设置 con.rollbackOnly = true,线程回到上层事务 commit 时会检查该字段,然后执行回滚操作 -
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK):回滚的后置处理 -
cleanupAfterCompletion(status):清理和恢复现场
提交方式
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 事务管理器的提交方法
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
public final void commit(TransactionStatus status) throws TransactionException {
// 已经完成的事务不需要提交了
if (status.isCompleted()) {
throw new IllegalTransactionStateException();
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 条件成立说明是当前的业务强制回滚
if (defStatus.isLocalRollbackOnly()) {
// 回滚逻辑,
processRollback(defStatus, false);
return;
}
// 成立说明共享当前事务的【下层事务逻辑出错,需要回滚】
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
// 如果当前事务还是事务重入,会继续抛给上层,最上层事务会进行真实的事务回滚操作
processRollback(defStatus, true);
return;
}
// 执行提交
processCommit(defStatus);
}
AbstractPlatformTransactionManager#processCommit:事务提交
-
prepareForCommit(status):前置处理 -
if (status.hasSavepoint()):条件成立说明当前事务是一个内嵌事务,只是复用了上层事务status.releaseHeldSavepoint():清理保存点,因为没有发生任何异常,所以保存点没有存在的意义了 -
if (status.isNewTransaction()):说明事务是归属于当前连接的,需要去提交事务doCommit(status):真正的提交函数Connection con = txObject.getConnectionHolder().getConnection():获取连接对象con.commit():JDBC 的方式提交事务
-
doRollbackOnCommitException(status, ex):提交事务出错后进行回滚 -
cleanupAfterCompletion(status):清理和恢复现场
清理现场
恢复上层事务:
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
// 从当前线程的 ThreadLocal 获取上层的事务信息,将当前事务出栈,继续执行上层事务
txInfo.restoreThreadLocalStatus();
}
}
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
transactionInfoHolder.set(this.oldTransactionInfo);
}
当前层级事务结束时的清理:
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
// 设置当前方法的事务状态为完成状态
status.setCompleted();
if (status.isNewSynchronization()) {
// 清理线程上下文变量以及扩展点注册的 sync
TransactionSynchronizationManager.clear();
}
// 事务是当前线程开启的
if (status.isNewTransaction()) {
// 解绑资源
doCleanupAfterCompletion(status.getTransaction());
}
// 条件成立说明当前事务执行的时候,【挂起了一个上层的事务】
if (status.getSuspendedResources() != null) {
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
// 恢复上层事务现场
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
DataSourceTransactionManager#doCleanupAfterCompletion:清理工作
-
TransactionSynchronizationManager.unbindResource(obtainDataSource()):解绑数据库资源 -
if (txObject.isMustRestoreAutoCommit()):是否恢复连接,Conn 归还到 DataSource**,归还前需要恢复到申请时的状态**con.setAutoCommit(true):恢复连接为自动提交 -
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel()):恢复隔离级别 -
DataSourceUtils.releaseConnection(con, this.dataSource):将连接归还给数据库连接池 -
txObject.getConnectionHolder().clear():清理 ConnectionHolder 资源
结尾
事务重入这方面的知识比较少接触 但是稍微了解一下 作为进阶知识
本文正在参加「金石计划 . 瓜分6万现金大奖」