事务的回滚

  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. 循序渐进搞懂 TCP 三次握手核心

    前言 本文旨在通过形象的例子和实操,把无形的.虚拟的网络转为具体的.可视化的.带领网络小白一步步的掌握 TCP 三次握手核心知识点,为后续深入学习 TCP 协议打基础. 通俗版 如下图所示,小明(客户 ...

  2. 基于STM32单片机的简单红外循迹的实现

    初步接触STM32,采用两路红外传感器实现小车循迹,稍显简略,如有不好的地方,欢迎大家指点改正

  3. (转)Angular中的拦截器Interceptor

    什么是拦截器? 异步操作 例子 Session 注入(请求拦截器) 时间戳(请求和响应拦截器) 请求恢复 (请求异常拦截) Session 恢复 (响应异常拦截器) 转之:http://my.osch ...

  4. 2021.08.09 P5658 括号树(树形结构)

    2021.08.09 P5658 括号树(树形结构) [P5658 CSP-S2019] 括号树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 太长,在链接中. 分析及代码 ...

  5. 2021.07.23 P2474 天平(差分约束)

    2021.07.23 P2474 天平(差分约束) [P2474 SCOI2008]天平 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 已知A,B和每两个点点权,求点权i, ...

  6. 使用 VS Code 撰写 Markdown 文档

    众所周知, VS Code 是微软和社区一起开发的一款很优秀的高级代码编辑器.它不仅可以写出一手好代码,还能写出一篇好文章.利用 Markdown 就可以写出一篇排版美观的技术文章了. 而 Markd ...

  7. baiyang网站二代域名及短链接

    http://985.so/wesv https://cloud.tencent.com/developer/column/93900

  8. XCTF练习题---MISC---a_good_idea

    XCTF练习题---MISC---a_good_idea flag:NCTF{m1sc_1s_very_funny!!!} 解题步骤: 1.观察题目,下载附件 2.到手以后发现是一张图片,尝试修改文件 ...

  9. XCTF练习题---CRYPTO---不仅仅是Morse

    XCTF练习题---CRYPTO---不仅仅是Morse flag:cyberpeace{attackanddefenceworldisinteresting} 解题步骤: 1.观察题目,下载附件 2 ...

  10. Linux-ssh-key验证

    ssh登录验证方式介绍 ssh服务登录的常用验证方式 用户/口令 基于密钥 基于用户和口令登录验证 客户端发起ssh请求,服务器会把自己的公钥发送给用户 用户会根据服务器发来的公钥对密码进行加密 加密 ...