Fescar - RM undoLog的介绍

简介: 开篇 这篇文章的目的是介绍Fescar当中回滚日志undoLog的数据结构,为后续RM执行回滚动作rollback打下基础,因为undoLog涉及的数据结构用源码表示起来比较简单通俗易懂,所以直接根据源码进行讲解。

开篇

 这篇文章的目的是介绍Fescar当中回滚日志undoLog的数据结构,为后续RM执行回滚动作rollback打下基础,因为undoLog涉及的数据结构用源码表示起来比较简单通俗易懂,所以直接根据源码进行讲解。


undoLog源码介绍

public class TableRecords {
    // 表元数据记录
    private TableMeta tableMeta;
    // 表名
    private String tableName;
    // 查询获得的行记录
    private List<Row> rows = new ArrayList<Row>();
}

public class Row {
    // 表的行记录其实表中列字段的集合,Field是column字段。
    private List<Field> fields = new ArrayList<Field>();
}

public class Field {

    // 列名
    public String name;

    private KeyType keyType = KeyType.NULL;

    // 列的字段类型。
    public int type;

    // 列的值
    public Object value;
}

说明:

  • 介绍UndoLog对象之前必须先了解构建UndoLog的原始记录beforeImage和afterImage对象。
  • TableRecords beforeImage = beforeImage()中TableRecords保存SQL执行前后数据镜像。
  • TableRecords顾名思义就是表当中的数据记录,保存从数据表中查询得到的行记录。
  • TableRecords中的List是行记录的集合。
  • Row中的List是单行当中的列字段column。
  • Field是描述单列的数据结构,包含列的字段名,字段类型,字段值等。


public abstract class BaseTransactionalExecutor<T, S extends Statement> implements Executor {

    protected void prepareUndoLog(TableRecords beforeImage, TableRecords afterImage) throws SQLException {
        if (beforeImage.getRows().size() == 0 && afterImage.getRows().size() == 0) {
            return;
        }

        ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();

        // 生成TC的全局锁对象lockKeys  
        TableRecords lockKeyRecords = sqlRecognizer.getSQLType() == SQLType.DELETE ? beforeImage : afterImage;

        // 根据SQL类型区分生成锁字段的原始素材
        String lockKeys = buildLockKey(lockKeyRecords);

        // 将锁字段保存到connectionProxy的维度
        connectionProxy.appendLockKey(lockKeys);

        // 准备SQLUndoLog
        SQLUndoLog sqlUndoLog = buildUndoItem(beforeImage, afterImage);

       // 将回滚日志保存到connectionProxy的维度
        connectionProxy.appendUndoLog(sqlUndoLog);
    }
}

说明:

  • 根据SQL类型区分生成锁字段的原始素材beforeImage或afterImage。
  • 将锁字段保存到connectionProxy的维度
  • 准备SQLUndoLog,通过beforeImage或afterImage。
  • 将回滚日志sqlUndoLog保存到connectionProxy的维度


public abstract class BaseTransactionalExecutor<T, S extends Statement> implements Executor {

    protected String buildLockKey(TableRecords rowsIncludingPK) {
        if (rowsIncludingPK.size() == 0) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(rowsIncludingPK.getTableMeta().getTableName());
        sb.append(":");

        boolean flag = false;
        for (Field field : rowsIncludingPK.pkRows()) {
            if (flag) {
                sb.append(",");
            } else {
                flag = true;
            }
            sb.append(field.getValue());
        }
        return sb.toString();
    }
}

说明:

  • 锁字段的生成逻辑是表名:primaryKey的列值。
  • 锁字段的生成逻辑是表名加pk的值。
  • 关注外层的for循环,如果变更多条记录即多个row记录,就拼接所有row记录的pk的值。


public class SQLUndoLog {
    // SQL的类型
    private SQLType sqlType;
    // 表名
    private String tableName;
    // 执行前镜像
    private TableRecords beforeImage;
    // 执行后镜像
    private TableRecords afterImage;
}


public abstract class BaseTransactionalExecutor<T, S extends Statement> implements Executor {

    protected SQLUndoLog buildUndoItem(TableRecords beforeImage, TableRecords afterImage) {
        SQLType sqlType = sqlRecognizer.getSQLType();
        String tableName = sqlRecognizer.getTableName();

        SQLUndoLog sqlUndoLog = new SQLUndoLog();
        sqlUndoLog.setSqlType(sqlType);
        sqlUndoLog.setTableName(tableName);
        sqlUndoLog.setBeforeImage(beforeImage);
        sqlUndoLog.setAfterImage(afterImage);

        return sqlUndoLog;
    }
}

说明:

  • SQLUndoLog的数据结构如上所示,包括SQL类型、表名、执行前后镜像。
  • buildUndoItem的构建UndoItem的逻辑就是保存上述提到的基础数据。


重点

 个人认为重点在于undoLog的lockKey的生成逻辑以及保存的容器在于connectionProxy对象。

目录
相关文章
|
4月前
|
开发者
seata事务问题之不回滚客户端如何解决
Seata是一款开源的分布式事务解决方案,旨在提供高效且无缝的分布式事务服务;在集成和使用Seata过程中,开发者可能会遇到不同的异常问题,本合集针对Seata常见异常进行系统整理,为开发者提供详细的问题分析和解决方案,助力高效解决分布式事务中的难题。
286 1
|
10月前
|
关系型数据库 PostgreSQL
PostgreSQL事务提交日志与CLOG操作初步认识
PostgreSQL事务提交日志与CLOG操作初步认识
156 0
RM在seata AT模式中如何实现分支事务提交或回滚
RM在seata AT模式中如何实现分支事务提交或回滚
381 0
|
SQL 数据库
源码解析Seata AT模式中分支事务的提交或回滚是如何被触发的
源码解析Seata AT模式中分支事务的提交或回滚是如何被触发的
277 0
源码解析Seata AT模式中分支事务的提交或回滚是如何被触发的
|
XML Java 中间件
Seata 分支事务
前面,我们已经介绍了 Seata 的整体设计思想,接下来我们深入到其实现细节中,本文先来介绍 Seata 中分支事务的整体实现思想。
|
SQL druid 关系型数据库
Seata AT 分支事务
前面,我们已经介绍了 Seata 的整体设计思想,接下来我们深入到其实现细节中,本文介绍 Seata 中 AT 模式分支事务的实现。
|
存储 Dubbo Java
Seata TCC 分支事务
前面,我们已经介绍了 Seata 的整体设计思想,接下来我们深入到其实现细节中,本文介绍 Seata 中 TCC 模式分支事务的实现。
|
存储 关系型数据库 MySQL
【分布式事务】面试官问我:如何恢复MySQL中的XA事务?
前段时间搭建了一套MySQL分布式数据库集群,数据库节点有12个,用来测试各种分布式事务方案的性能和优缺点。测试MySQL XA事务时,正当测试脚本向数据库中批量插入数据时,强制服务器断电!注意:是直接拔电源,使其瞬间断电,再次重启服务器后,MySQL数据库报错了。特此记录MySQL XA事务的恢复。
225 0
|
存储 关系型数据库 MySQL
【分布式事务】面试官问我:MySQL中的XA事务崩溃了如何恢复??
前段时间搭建了一套MySQL分布式数据库集群,数据库节点有12个,用来测试各种分布式事务方案的性能和优缺点。测试MySQL XA事务时,正当测试脚本向数据库中批量插入数据时,强制服务器断电!注意:是直接拔电源,使其瞬间断电,再次重启服务器后,MySQL数据库报错了。特此记录MySQL XA事务的恢复。
192 0
|
关系型数据库 MySQL 数据库
从一个问题出发,搞懂MySQL MVCC、readview、快照读和undo log是什么鬼
摸鱼的时候看到某技术群里有一个问题和下面的回复
1374 0
从一个问题出发,搞懂MySQL MVCC、readview、快照读和undo log是什么鬼