事务的回滚

  1. 如果获取事务属性不为空,并且抛出的异常是RuntimeException或者Error类型,调用事务管理器中的rollback方法进行回滚

  2. 如果事务属性为空或者抛出的异常不是RuntimeException,也不是Error,将继续提交事务

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {

       /**
* 处理抛出异常下的事务
*/
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);
}
// 如果事务属性不为空并且异常是是RuntimeException或者Error
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 获取事务管理器,调用rollback方法进行回滚
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 {
// 如果事务属性为空或者异常不是RuntimeException或者Error,继续提交事务
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;
}
}
}
}
} // DefaultTransactionAttribute中实现了rollbackOn方法
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
/**
* 判断是否是RuntimeException或者Error
*/
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
}

rollback方法在AbstractPlatformTransactionManager中实现,主要分为以下三种情况:

  1. 判断事务是否设置了保存点,如果设置了将事务回滚到保存点
  2. 如果是一个独立的新事务,直接回滚即可
  3. 如果既没有设置保存点,也不是一个新事务,说明可能处于嵌套事务中,此时只设置回滚状态rollbackOnly为true,当它的外围事务进行提交时,如果发现回滚状态为true,则不提交

以上步骤执行完毕,调用cleanupAfterCompletion方法进行资源的清理已经挂起事务的恢复。

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
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 处理回滚
processRollback(defStatus, false);
} /**
* 处理回滚
*/
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected; try {
// 回滚之前的触发器
triggerBeforeCompletion(status);
// 是否有保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
// 回滚至保存点
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) { // 如果是一个独立的新事务
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
// 直接回滚
doRollback(status);
}
else {
// 如果处于一个嵌套的事务汇总
if (status.hasTransaction()) {
// 如果本地的回滚状态置为true 或者 事务失败进行全局回滚
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
// 设置事务rollbackOnly状态为true
doSetRollbackOnly(stat);
}
else {
// 打印日志,意思是由事务的组织者决定是否回滚
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
// 打印DEBUG日志,应该回滚但是没有获取到事务
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 回滚之后的触发器
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 {
// 清除相关资源并恢复挂起的事务
cleanupAfterCompletion(status);
}
} /**
* 当一个事务失败以后,是否全局的标进行事务回滚
*/
public final boolean isGlobalRollbackOnParticipationFailure() {
return this.globalRollbackOnParticipationFailure;
} }

回滚处理

rollbackToHeldSavepoint回滚至保存点

rollbackToHeldSavepoint方法在AbstractTransactionStatus中实现,它调用了getSavepointManager方法获取保存点管理器,调用SavepointManager的rollbackToSavepoint方法进行回滚的:

public abstract class AbstractTransactionStatus implements TransactionStatus {

	public void rollbackToHeldSavepoint() throws TransactionException {
Object savepoint = getSavepoint();
if (savepoint == null) {
throw new TransactionUsageException(
"Cannot roll back to savepoint - no savepoint associated with current transaction");
}
// getSavepointManager方法在DefaultTransactionStatus中实现
getSavepointManager().rollbackToSavepoint(savepoint);
getSavepointManager().releaseSavepoint(savepoint);
setSavepoint(null);
}
}

SavepointManager是一个接口,它的继承关系如下:

DefaultTransactionStatus中获取SavepointManager的方法:

  1. 获取transaction对象,前面的知识可知这里是一个DataSourceTransactionObject
  2. 由继承关系可知DataSourceTransactionObject也是SavepointManager子类,所以将DataSourceTransactionObject转为SavepointManager返回
public class DefaultTransactionStatus extends AbstractTransactionStatus {
@Override
protected SavepointManager getSavepointManager() {
// 前面的知识可知这里是一个DataSourceTransactionObject
Object transaction = this.transaction;
if (!(transaction instanceof SavepointManager)) {
throw new NestedTransactionNotSupportedException(
"Transaction object [" + this.transaction + "] does not support savepoints");
}
// 将DataSourceTransactionObject转为SavepointManager
return (SavepointManager) transaction;
}
}

DataSourceTransactionObject是DataSourceTransactionManager的内部类,它继承了JdbcTransactionObjectSupport,rollbackToSavepoint方法在JdbcTransactionObjectSupport中实现:

  1. 获取ConnectionHolder,ConnectionHolder持有数据库连接
  2. 调用底层的rollback方法将事务回滚至保存点
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
// 内部类DataSourceTransactionObject
private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport { }
} // JdbcTransactionObjectSupport
public abstract class JdbcTransactionObjectSupport implements SavepointManager, SmartTransactionObject {
/**
* 回滚至保存点
*/
@Override
public void rollbackToSavepoint(Object savepoint) throws TransactionException {
// 获取ConnectionHolder
ConnectionHolder conHolder = getConnectionHolderForSavepoint();
try {
// 调用底层的rollback方法将事务回滚至保存点
conHolder.getConnection().rollback((Savepoint) savepoint);
conHolder.resetRollbackOnly();
}
catch (Throwable ex) {
throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
}
} /**
* 释放保存点
*/
@Override
public void releaseSavepoint(Object savepoint) throws TransactionException {
ConnectionHolder conHolder = getConnectionHolderForSavepoint();
try {
// 调用底层的方法释放保存点
conHolder.getConnection().releaseSavepoint((Savepoint) savepoint);
}
catch (Throwable ex) {
logger.debug("Could not explicitly release JDBC savepoint", ex);
}
}
}

doRollback事务回滚

回滚事务时先获取数据库连接,然后调用底层的rollback进行回滚:

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean { @Override
protected void doRollback(DefaultTransactionStatus status) {
// 获取数据源事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// 获取数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
// 调用底层的回滚方法
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
}

doSetRollbackOnly设置回滚状态

doSetRollbackOnly方法在DataSourceTransactionManager中实现:

  1. 将事务转为DataSourceTransactionObject对象,前面讲过DataSourceTransactionObject持有了数据库连接对象ConnectionHolder

  2. 将ConnectionHolder的rollbackOnly属性置为true,先标记事务的回滚状态,交由外围事务进行判断统一进行回滚

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean { @Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
// 获取数据源事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
"] rollback-only");
}
// 设置回滚状态
txObject.setRollbackOnly();
} /**
* 内部类DataSourceTransactionObject
*/
private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport { // 省略其他方法 // 设置回滚状态
public void setRollbackOnly() {
// 将ConnectionHolder的rollbackOnly属性置为true,在ConnectionHolder的父类ResourceHolderSupport中实现
getConnectionHolder().setRollbackOnly();
} } } // ConnectionHolder的父类ResourceHolderSupport
public abstract class ResourceHolderSupport implements ResourceHolder { private boolean rollbackOnly = false; /**
* 标记事务回滚状态为true
*/
public void setRollbackOnly() {
this.rollbackOnly = true;
} }

资源清理

在事务回滚之后,需要清理相关的资源以及恢复被挂起的事务:

  1. 如果事务的newSynchronization状态为true,清除当前线程绑定的事务相关信息

    • 在TransactionSynchronizationManager的clear方法中实现,清理了当前线程绑定的事务名称、事务隔离级别等信息
  2. 如果是一个新事务,清除当前线程与数据库连接的绑定关系,在DataSourceTransactionManager的doCleanupAfterCompletion方法中实现
  3. 如果挂起的事务不为空,恢复挂起的事务
    • 获取数据源,恢复数据源与挂起事务的绑定关系
    • 恢复挂起事务与当前线程的同步信息
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

        /**
* 回滚之后的清除操作
* @see #doCleanupAfterCompletion
*/
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
// 清除当前线程绑定的信息
TransactionSynchronizationManager.clear();
}
// 如果是一个新事务
if (status.isNewTransaction()) {
// 清除当前线程与数据库连接的绑定关系
doCleanupAfterCompletion(status.getTransaction());
}
// 如果挂起的事务不为空
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
// 恢复挂起的事务
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
} /**
* 恢复挂起的事务
* @see #doResume
* @see #suspend
*/
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
throws TransactionException { if (resourcesHolder != null) {
// 获取挂起的事务
Object suspendedResources = resourcesHolder.suspendedResources;
if (suspendedResources != null) {
// 获取数据源,并与挂起的事务进行绑定
doResume(transaction, suspendedResources);
}
// 挂起事务的同步信息
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);
}
}
}
} // DataSourceTransactionManager
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
// 主要是清除当前线程与数据库连接的绑定关系
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; // Remove the connection holder from the thread, if exposed.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(obtainDataSource());
} // 获取数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
// 自动提交置为true
con.setAutoCommit(true);
}
// 重置数据库连接的相关设置
DataSourceUtils.resetConnectionAfterTransaction(
con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
} if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
// 释放连接
DataSourceUtils.releaseConnection(con, this.dataSource);
}
// 清除当前线程与数据库连接的绑定关系
txObject.getConnectionHolder().clear();
} @Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
// 获取数据源,并与挂起的事务进行绑定
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
} // TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager { // 保存了线程绑定的数据库资源信息,Map中Key为数据源构建的KEY,value为对应的ConnectionHolder
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 保存了线程绑定的事务同步信息TransactionSynchronization
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations"); // 保存了线程绑定的事务名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 保存了线程绑定的事务只读状态
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");
// 保存了线程绑定的事务活跃状态
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active"); /**
* 清理事务与当前线程的各种同步状态
*/
public static void clear() {
// 清除当前线程绑定的事务同步信息TransactionSynchronization
synchronizations.remove();
// 清除当前线程绑定的事务名称
currentTransactionName.remove();
// 清除线程绑定的事务只读状态
currentTransactionReadOnly.remove();
// 清除线程绑定的事务隔离级别
currentTransactionIsolationLevel.remove();
// 清除线程绑定的事务活跃状态
actualTransactionActive.remove();
} }

总结

参考

【猫吻鱼】Spring源码分析:全集整理

Spring版本:5.2.5.RELEASE

【Spring】事务的执行原理(三)的更多相关文章

  1. spring的MVC执行原理

    spring的MVC执行原理 1.spring mvc将所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求 进行真正的处理工作. 2.DispatcherSer ...

  2. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  3. 【Srping】事务的执行原理(一)

    在使用事务的时候需要添加@EnableTransactionManagement注解来开启事务,那么就从@EnableTransactionManagement入手查看一下事务的执行原理. @Enab ...

  4. 【Spring】事务的执行原理(二)

    前置知识 事务的执行步骤如下: 获取事务管理器 创建事务 执行目标方法 捕捉异常,如果出现异常进行回滚 提交事务 public abstract class TransactionAspectSupp ...

  5. spring事务管理实现原理-源码-传播属性

    转载请标识 https://me.csdn.net/wanghaitao4j https://blog.csdn.net/wanghaitao4j/article/details/83625260 本 ...

  6. Spring事务之详解--三种实现方式

    实现购买股票案例: 一.引入JAR文件: 二.开始搭建分层架构---创建账户(Account)和股票(Stock)实体类 Account: /* * 账户 */ public class Accoun ...

  7. spring not_support 该方法被事务方法调用时 不会加入spring事务 只是执行jdbc普通的事务

  8. Spring事务用法示例与实现原理

    关于Java中的事务,简单来说,就是为了保证数据完整性而存在的一种工具,其主要有四大特性:原子性,一致性,隔离性和持久性.对于Spring事务,其最终还是在数据库层面实现的,而Spring只是以一种比 ...

  9. Spring事务原理一探

    概括来讲,事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据 一致以及操作隔离.数据一致是指事务提交时保证事务内的所有操作都成功完成,并且 更改永久生效:事务回滚时,保证能够恢复到事务 ...

随机推荐

  1. Masa Blazor in Blazor Day

    2022年第一场Blazor中文社区的开发者分享活动,我们的团队也全程参与其中,在议程中,也分享了我们团队的Blazor 管理后台模板,针对于Blazor,先科普一波,避免有些朋友不了解,Blazor ...

  2. Java中的List接口实现类LinkedList

    package collection; import java.util.LinkedList; /* * 1.implement List接口 * 2.底层是一个链表结构:查询慢,增删快 * 注意: ...

  3. zabbix3.2 监控MongoDB

    本文参考连接: https://www.jianshu.com/p/a6b36d5b74ba 一.实验环境: MongoDB/zabbix-agent:172.16.88.44 zabbix-serv ...

  4. java实现sftp文件上传下载

    /** * * @param filePath 文件全路径 * @param ftpPath 上传到目的端目录 * @param username * @param password * @param ...

  5. Hadoop-Hive组件部署

    一.基础环境 Hive 组件需要基于之前已部署完毕的 Hadoop 全分布系统,在 master 节点上实现 Hive 组件安装. 1.Hadoop-全分布式配置(全部配置) 2.Hadoop-集群运 ...

  6. 2021.11.05 eleveni的水省选题的记录

    2021.11.05 eleveni的水省选题的记录 因为eleveni比较菜,但是eleveni不想写绿题(总不能说是被绿题虐得不想写),eleveni决定继续水noip原题. --实际上菜菜的el ...

  7. python基础练习题(题目 学习使用auto定义变量的用法)

    day28 --------------------------------------------------------------- 实例042:变量作用域 题目 学习使用auto定义变量的用法 ...

  8. 华为麒麟团队力造的Python,整整26G

    华为团队力造的Python,下面链接自取 https://docs.qq.com/doc/DRkZvRkxvb292c2Vz

  9. 『现学现忘』Git基础 — 14、Git基础操作的总结与补充

    目录 1.Git本地版本库结构 2.Git常用操作方法 3.补充:添加多个文件到暂存区 4.补充:提交操作未写备注 5.补充:从工作区直接提交到版本库 1.Git本地版本库结构 如下图所示: 工作区( ...

  10. Redis为什么变慢了?透彻解读如何排查Redis性能问题

    Redis 作为优秀的内存数据库,其拥有非常高的性能,单个实例的 OPS 能够达到 10W 左右.但也正因此如此,当我们在使用 Redis 时,如果发现操作延迟变大的情况,就会与我们的预期不符. 你也 ...