四、全局事务的commit和rollback

所有文章

https://www.cnblogs.com/lay2017/p/12485081.html

正文

上一篇文章中,我们看了看DefaultCoordinator作为分布式事务的协调者,关于全局事务begin的流程。

DefaultCoordinator把begin的核心实现交付给了DefaultCore,DefaultCore将会构造处一个GlobalSession,一份放到内存里面,一份持久化(默认持久化到 ~/sessionStore/root.data)。

总结下来就是begin的时候将会在Server端构造一个GlobalSession。

那么,本文将看看关于全局事务的commit是怎么样一个流程。

DefaultCore.commit

和begin一样,DefaultCoordinator把commit全局事务的实现交付给了DefaultCore来做。我们打开DefaultCore的commit方法

@Override
public GlobalStatus commit(String xid) throws TransactionException {
    // 通过XID找到GlobalSession
    GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
    if (globalSession == null) {
        return GlobalStatus.Finished;
    }

    // 添加FileTransactionStoreManager
    globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());

    // 加锁
    boolean shouldCommit = globalSession.lockAndExcute(() -> {
        // 关闭session,防止还有分支事务注册
        globalSession.closeAndClean();
        if (globalSession.getStatus() == GlobalStatus.Begin) {
            // 状态变化
            globalSession.changeStatus(GlobalStatus.Committing);
            return true;
        }
        return false;
    });

    // 如果原本不是begin的状态,返回原本状态
    if (!shouldCommit) {
        return globalSession.getStatus();
    }

    // 判断是否可以异步提交
    if (globalSession.canBeCommittedAsync()) {
        // 异步提交
        asyncCommit(globalSession);
        return GlobalStatus.Committed;
    } else {
        // 同步提交
        doGlobalCommit(globalSession, false);
    }
    // 返回状态
    return globalSession.getStatus();
}

commit方法比较长,但是逻辑并不复杂

1)首先,先根据XID找到对应的GlobalSession。

2)其次,将GlobalSession的状态从begin到committing表示正在执行提交

3)然后,进行提交操作。

findGlobalSession方法将从file或者db中查询GlobalSession,changeStatus的时候先close了当前全局事务,这样就不会有新的分支事务注册进来了。

canBeCommittedAsync将判断是否可以进行异步提交,判断标准是什么呢?我们看看该方法

public boolean canBeCommittedAsync() {
    // 遍历分支session
    for (BranchSession branchSession : branchSessions) {
        // 如果有一个TCC分支返回false
        if (branchSession.getBranchType() == BranchType.TCC) {
            return false;
        }
    }
    return true;
}

这里判断的是分支事务的session是TCC类型。

也就是说,如果当前GlobalSession代表的是AT自动事务模式。那么只需要将GlobalSession的状态改为AsyncCommitting即可,而通知RM端的事情交给DefaultCoordinator的异步线程来做。如果包含TCC分支,那么直接调用doGlobalCommit同步提交。

我们再看看DefaultCoordinator的异步线程怎么处理AT模式的的。

asyncCommitting.scheduleAtFixedRate(() -> {
    try {
        handleAsyncCommitting();
    } catch (Exception e) {
        LOGGER.info("Exception async committing ... ", e);
    }
}, 0, ASYNC_COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS);

protected void handleAsyncCommitting() {
    // 获取所有AsyncCommitting状态的GlobalSession
    Collection<GlobalSession> asyncCommittingSessions = SessionHolder.getAsyncCommittingSessionManager().allSessions();
    if (CollectionUtils.isEmpty(asyncCommittingSessions)) {
        return;
    }
    // 遍历session
    for (GlobalSession asyncCommittingSession : asyncCommittingSessions) {
        try {
            if (GlobalStatus.AsyncCommitting != asyncCommittingSession.getStatus()) {
                continue;
            }
            asyncCommittingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
            // 调用core的doGlobalCommit通知客户端
            core.doGlobalCommit(asyncCommittingSession, true);
        } catch (TransactionException ex) {
            // ...
        }
    }
}

异步线程默认1秒中执行一次,将从SessionManager中获取所有AsyncCommitting状态的GlobalSession。

然后逐个调用DefaultCore的doGlobalCommit方法通知客户端删除undoLog。

DefaultCore.rollback

上面看了全局事务的commit,那么rollback呢?我们跟进DefaultCore的rollback代码

@Override
public GlobalStatus rollback(String xid) throws TransactionException {
    // 找到GlobalSession
    GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
    if (globalSession == null) {
        return GlobalStatus.Finished;
    }
    globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
    // 加锁
    boolean shouldRollBack = globalSession.lockAndExcute(() -> {
        // 先关闭
        globalSession.close();
        // 状态变更
        if (globalSession.getStatus() == GlobalStatus.Begin) {
            globalSession.changeStatus(GlobalStatus.Rollbacking);
            return true;
        }
        return false;
    });
    if (!shouldRollBack) {
        return globalSession.getStatus();
    }
    // 直接同步处理
    doGlobalRollback(globalSession, false);
    return globalSession.getStatus();
}

rollback比commit逻辑简单多了,也不用同步异步的区分。直接都是同步遍历所有分支事务的session,通知RM进行rollback操作。

总结

全局事务的提交,无非是从file或者db中拿到GlobalSession。不论是同步提交还是异步提交,最终都是拿到所有分支事务的session,然后通知RM去做相应的commit操作。

全局事务的回滚,一样是拿到GlobalSession。然后通知RM做分支事务的rollback操作。

总得来说,Server端主动推送commit或者rollback通知到RM,如果失败那么就进行retry。seata在一致性方面选择了最终一致性。

原文地址:https://www.cnblogs.com/lay2017/p/12507557.html

时间: 2024-10-26 22:58:37

四、全局事务的commit和rollback的相关文章

JDBC Tutorials: Commit or Rollback transaction in finally block

http://skeletoncoder.blogspot.com/2006/10/jdbc-tutorials-commit-or-rollback.html JDBC Tutorials: Commit or Rollback transaction in finally block In most of JDBC books, the transaction management idiom that is followed is, after executing the update s

START TRANSACTION, COMMIT, and ROLLBACK Syntax-from cyber

START TRANSACTION [WITH CONSISTENT SNAPSHOT] BEGIN [WORK] COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] SET autocommit = {0 | 1} These statements provide control over use of transactions: START TRANSACT

oracle的启动与关闭原理-事务commit或者rollback

4.事务 4.1事务的概念 从第一个DML语句开始执行,以rollback或者commit为结束标记,之前所有的DML操作(insert,update,delete )都是属于这个事务的范围内. 4.2 事务的提交操作 (1)首先解锁一个用户并改密码 SQL> alter user scott account unlock; User altered. SQL> alter user scott identified by scott; User altered. (2)连接到scott用户S

COMMIT和ROLLBACK的用法

从功能上划分,SQL语言可以分为DDL,DML和DCL三大类. 1.DDL(Data Definition Language)  数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言 : CREATE---创建表 ALTER---修改表 DROP---删除表 2. DML(Data Manipulation Language)  数据操纵语言,SQL中处理数据等操作统称为数据操纵语言 :  INSERT---数据的插入 DELETE---数据的删除 UPDATE---数据的修改 SEL

MYSQL的COMMIT和ROLLBACK

从功能上划分,SQL 语言可以分为DDL,DML和DCL三大类. 1. DDL(Data Definition Language)      数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言 :     CREATE---创建表     ALTER---修改表     DROP---删除表 2. DML(Data Manipulation Language)      数据操纵语言,SQL中处理数据等操作统称为数据操纵语言 :      INSERT---数据的插入     DEL

git第四节----git commit message

@git  commit message 什么是git commit message :git commit -m '每次提交时编辑的内容' git commit message的好处:      1.提供更多可查询的信息,用于排查问题      2.过滤重要的内容      3.生成changelog     commit message组成包括header,body,footer三个部分,一般只使用header    header 包含三个部分:type,scope,subject     

《oracle每天一练》触发器不能调用或间接调用COMMIT,ROLLBACK等DCL语句

触发器不能调用或间接调用COMMIT,ROLLBACK等DCL语句 在触发器中不能运行 ddl语句和commit,rollback语句 ddl语句:DDL语句用语定义和管理数据库中的对象,如Create,Alter,Drop,truncate等:DDL操作是隐性提交的!         操作立即生效,原数据不放到rollback segment中,不能回滚. 操作不触发trigger DML(Data Manipulation Language)数据操纵语言命令使用户能够查询数据库以及操作已有数

Spring笔记(四): spring的编程式事务与声明式事务

一.Spring 事务属性分析 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失. 在 Spring 中,事务是通过 TransactionDefinition 接口来定义的.该接口包含与事务属性有关的方法.在

Spring学习笔记(四)-- Spring事务全面分析

通过本系列的文章对Spring的介绍,我们对Spring的使用和两个核心功能IOC.AOP已经有了初步的了解,结合我个人工作的情况,由于项目是金融系 统,那对事务的控制是必不可少的,并且是非常严格的控制.根据我对项目的研究,它在管理模块用的是JTA的事务,而在交易模块用的是JDBC的事 务,但是,所有的这些事务的使用,都是用Spring封装后的编程式事务.我在看完<Spring In Action>后,在网上看了下大家对Spring事务的理解,貌 似都没有真正的文章是去全面剖析Spring对这