解密seata全局锁

  • 从哪开始分析呢?
  • StatementProxy
  • ExecuteTemplate
  • executeAutoCommitFalse
  • 总结

从哪开始分析呢?

seata的基本原理可以参照2PC, 而本地事务方面的实现是通过代理方式实现扩展, 如: 在执行提交前后生成image等

StatementProxy

  • 熟悉JDBC的同学应该都知道Statement的作用吧, seata实现Statement功能的代理类就是StatementProxy

  • 通过观察StatementProxy里面的方法可以发现所有的操作基本都是委派给ExecuteTemplate实现的

    @Overridepublic int executeUpdate(String sql) throws SQLException {this.targetSQL = sql;return ExecuteTemplate.execute(this, (statement, args) -> statement.executeUpdate((String) args[0]), sql);}
    

ExecuteTemplate

  • 继续追踪execute()方法, 上面的内容主要是做一些执行前的判断, 还有就是选择合适的Executor, 如UpdateExecutor

  • 我们只关注较为核心的executor.execute(args)

        public static <T, S extends Statement> T execute(List<SQLRecognizer> sqlRecognizers,StatementProxy<S> statementProxy,StatementCallback<T, S> statementCallback,Object... args) throws SQLException {...T rs;try {// 核心代码rs = executor.execute(args);} catch (Throwable ex) {if (!(ex instanceof SQLException)) {// Turn other exception into SQLExceptionex = new SQLException(ex);}throw (SQLException) ex;}return rs;}
    
  • 继续则可以一直追踪到io.seata.rm.datasource.exec.AbstractDMLBaseExecutor#doExecute

    @Overridepublic T doExecute(Object... args) throws Throwable {AbstractConnectionProxy connectionProxy = statementProxy.getConnectionProxy();// 通过判断是否自动提交分别执行方法, 这里我们只关注executeAutoCommitFalse, 感兴趣的同学查看executeAutoCommitTrue原理一探究竟if (connectionProxy.getAutoCommit()) {return executeAutoCommitTrue(args);} else {return executeAutoCommitFalse(args);}}
    

executeAutoCommitFalse

executeAutoCommitFalse主要做了这么几件事

  • 判断只有mysql支持复合主键
  • 执行语句之前生成beforeImage
  • 执行语句
  • 执行语句之后生成afterImage
  • 根据beforeImage和afterImage生成UndoLog
    protected T executeAutoCommitFalse(Object[] args) throws Exception {if (!JdbcConstants.MYSQL.equalsIgnoreCase(getDbType()) && getTableMeta().getPrimaryKeyOnlyName().size() > 1){throw new NotSupportYetException("multi pk only support mysql!");}TableRecords beforeImage = beforeImage();T result = statementCallback.execute(statementProxy.getTargetStatement(), args);TableRecords afterImage = afterImage(beforeImage);prepareUndoLog(beforeImage, afterImage);return result;}
  • 我们先来大体看一下beforeImage到底是在干什么

    @Overrideprotected TableRecords beforeImage() throws SQLException {ArrayList<List<Object>> paramAppenderList = new ArrayList<>();// 获取数据表元数据信息TableMeta tmeta = getTableMeta();// 构建一个select语句, tmeta里有表名, paramAppenderList用来存储参数String selectSQL = buildBeforeImageSQL(tmeta, paramAppenderList);// 核心操作return buildTableRecords(tmeta, selectSQL, paramAppenderList);}
    
        protected TableRecords buildTableRecords(TableMeta tableMeta, String selectSQL, ArrayList<List<Object>> paramAppenderList) throws SQLException {...// 执行获取的select语句, 将结果集rs传入, 接下来方法执行的就是取出结果集的操作, 这里不再深追return TableRecords.buildRecords(tableMeta, rs);} finally {IOUtil.close(rs);}}
    
  • afterImage原理相同, 也就是说beforeImageafterImage的作用就是把执行操作之前的结果集和执行操作之后的结果集查询出来

  • 接下来我们看prepareUndoLog方法

        protected void prepareUndoLog(TableRecords beforeImage, TableRecords afterImage) throws SQLException {if (beforeImage.getRows().isEmpty() && afterImage.getRows().isEmpty()) {return;}ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();TableRecords lockKeyRecords = sqlRecognizer.getSQLType() == SQLType.DELETE ? beforeImage : afterImage;// 构建全局锁的keyString lockKeys = buildLockKey(lockKeyRecords);connectionProxy.appendLockKey(lockKeys);SQLUndoLog sqlUndoLog = buildUndoItem(beforeImage, afterImage);connectionProxy.appendUndoLog(sqlUndoLog);}
    
  • buildLockKey()方法

    • 注意注释中的return, 说明了构建的全局锁的key到底长什么样, 具体构建过程先省略了, 其实就是把记录中包含的所有主键按照规律拼接字符串
    /*** build lockKey** @param rowsIncludingPK the records* @return the string as local key. the local key example(multi pk): "t_user:1_a,2_b"*/protected String buildLockKey(TableRecords rowsIncludingPK) {...}
    
  • buildUndoItem()方法

    /*** build a SQLUndoLog** @param beforeImage the before image* @param afterImage  the after image* @return sql undo log*/protected SQLUndoLog buildUndoItem(TableRecords beforeImage, TableRecords afterImage) {// 获取sql类型和表名, 创建sqlundoLog对象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;}
    

总结

通过上面的分析我们知道了:

  1. beforeImage和afterImage是在执行sql之前和之后查询的结果集
  2. 全局锁的key是由结果集中的主键按照一定规律拼接而成
  3. undoLog由beforeImage和afterImage组成

解密seata全局锁(一)相关推荐

  1. xa 全局锁_分布式事务如何实现?深入解读 Seata 的 XA 模式

    原标题:分布式事务如何实现?深入解读 Seata 的 XA 模式 作者简介:煊檍,GitHub ID:sharajava,阿里巴巴中件间 GTS 研发团队负责人,SEATA 开源项目发起人,曾在 Or ...

  2. mysql 写锁需要等待读锁释放吗_Mysql实战45讲笔记:5、全局锁和表锁

    全局锁: 对整个数据库实例加锁. MySQL提供加全局读锁的方法:Flush tables with read lock(FTWRL) 这个命令可以使整个库处于只读状态.使用该命令之后,数据更新语句. ...

  3. mysql怎么加全局锁_MySQL锁机制/管理(并发锁,行锁,表锁,预加锁,全局锁等等)

    MySQL实验室 1.?MySQL 中并发和隔离控制机制 Meta-data元数据锁:在table cache缓存里实现的,为DDL(Data Definition Language)提供隔离操作.一 ...

  4. Redis实现分布式锁全局锁—Redis客户端Redisson中分布式锁RLock实现

    2019独角兽企业重金招聘Python工程师标准>>> 1. 前因 以前实现过一个Redis实现的全局锁, 虽然能用, 但是感觉很不完善, 不可重入, 参数太多等等. 最近看到了一个 ...

  5. Fescar 全局锁介绍

    开篇  这篇文章的目的主要是讲解TC的在处理分支事务注册过程中对全局锁的处理流程,理解了全局锁以后才能明白对DB同一个记录进行多次变更是如何解决的.  如上图所示,问最终全局事务A对资源R1应该回滚到 ...

  6. MySQL 全局锁和表锁

    日常读书笔记 全局锁 含义和命令行 典型使用场景 注意点 问题:备份一定要加锁吗? 问题:既然备份不一定要加锁,那全局锁存在的意义是什么? 表级锁 表锁 命令行 所释放时机 锁时的具体细节 元数据锁 ...

  7. xa 全局锁_fescar锁设计和隔离级别的理解

    Fescar全局锁的理解 前几天夜里,我老大发我一篇文章说阿里的GTS开源了. 因为一直对分布式事务比较感兴趣.立马pull了代码,进行阅读. 基本的原理,实现方案我就不一一细化了,详细见官方文档(写 ...

  8. 06 | 全局锁和表锁 : 给表加个字段怎么有这么多阻碍

    引言   根据加锁的范围,MySQL 里面的锁大致可以分成全局锁.表级锁和行锁三类.这篇文章,与你分享全局锁和表级锁.而关于行锁的内容,我会留着在下一篇文章中再和你详细介绍. 全局锁   全局锁就是对 ...

  9. mysql ddl 锁_MySQL Online DDL导致全局锁表案例分析

    MySQL Online DDL导致全局锁表案例分析 我这边遇到了什么问题? 线上给某个表执行新增索引SQL, 然后整个数据CPU打到100%, 连接数暴增到极限, 最后导致所有访问数据库的应用都奔溃 ...

最新文章

  1. 阻止应用继承的NTFS权限
  2. C/C++基础问题归集
  3. 百度地图API —— Hello World!
  4. 浩鲸科技基于ChaosBlade的混沌工程实践
  5. 中台做不好,就会成为“钟台”!阿里高管离职创业,这次会搞砸吗
  6. IS-IS基础网络配置实例
  7. linux I2C读写应用程序
  8. 双三次插值算法(bicubic interpolation)与图形学和计算方法的关系
  9. xsmax进入dfu模式_DFU模式是什么?苹果XR/XS Max的DFU模式进入与退出方法[多图]
  10. 华为p9总显示切换服务器中,怎么更改华为p9的多任务切换 | 手游网游页游攻略大全...
  11. 函数的应用及其解析大全!
  12. 支付宝自动续费申请PHP,支付宝自动续费怎么取消?
  13. 宝塔 cpanel_cPanel / WHM许可更改
  14. Cadence常规通孔焊盘的创建
  15. AtCoder Beginner Contest 242 C 1111gal password
  16. 我看过《隐秘的角落》才知道,理科生有多可怕!
  17. 【转】关于Alipay支付宝接口(Java版)
  18. Linux小项目-倒车影像功能设计
  19. Symbian 模拟器在Vista Win7下无法正常启动
  20. 开关电源环路稳定性分析(09)——环路补偿六步法

热门文章

  1. 【语音控制ROS】PocketPhinx语音包的使用<三>
  2. ArcGIS入门教程(矢量编辑工作流程)
  3. MyBatisPlus自动填充
  4. ensp中路由器(华为设备)的基本使用
  5. D3 二维图表的绘制系列(二十三)旭日图
  6. 小米总监说软件测试分为这及类
  7. 把中文目录名称修改成英文首字母大写或中文拼音目录
  8. 即日起,发放三种勋章公告。
  9. 针织面料的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  10. Layer 打开新页面