MySQL事务提交过程(二)

2023-11-19

| 异步2周年,技术图书免费选     程序员8月书讯     项目管理+代码托管+文档协作,开发更流畅
2017-01-01 21:18 389人阅读 评论(0) 收藏 举报
分类:

上一篇文章我们介绍了在关闭binlog的情况下,事务提交的大概流程。之所以关闭binlog,是因为开启binlog后事务提交流程会变成两阶段提交,这里的两阶段提交并不涉及分布式事务,当然MySQL把它称之为内部xa事务(Distributed Transactions),与之对应的还有一个外部xa事务。

这里所谓的两阶段提交分别是prepare阶段和commit阶段。

内部xa事务主要是mysql内部为了保证binlog与redo log之间数据的一致性而存在的,这也是由其架构决定的(binlog在mysql层,而redo log 在存储引擎层);

外部xa事务则是指支持多实例分布式事务,这个才算是真正的分布式事务。

既然是xa事务,必然涉及到两阶段提交,对于内部xa而言,同样存在着提交的两个阶段。

下文会结合源码详细解读内部xa的两阶段提交过程,以及各种情况下,mysqld crash后,mysql如何恢复来保证事务的一致性。

   

测试环境

OS:WIN7

ENGINE:

DB:

   

配置文件参数:

log-bin=D:\mysql\log\5-6-21\mysql-bin

binlog_format=ROW

set autocommit=0;

innodb_support_xa=1

sync_binlog=1;

innodb_flush_log_at_trx_commit=1;

【innodb_flush_log_at_trx_commit=1,sync_binlog=1

不同的模式区别在于,写文件调用write和落盘fsync调用的频率不同,所导致的后果是mysqld 或 os crash后,不严格的设置可能会丢失事务的更新。

双一模式是最严格的模式,这种设置情况下,单机在任何情况下不会丢失事务更新。】

   

测试条件

set autocommit=0;
-- ----------------------------

-- Table structure for `user`

-- ----------------------------

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (

`id` int(20) NOT NULL,

`account` varchar(20) NOT NULL,

`name` varchar(20) NOT NULL,

PRIMARY KEY (`id`),

KEY `id` (`id`) USING BTREE,

KEY `name` (`name`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

   

测试语句

insert into user values(1, 'sanzhang', '张三');
commit;

   

prepare阶段:

    1.设置undo state=TRX_UNDO_PREPARED //trx_undo_set_state_at_prepare调用

    2.刷事务更新产生的redo日志;【步骤1产生的redo日志也会刷入】

MYSQL_BIN_LOG::prepare

ha_prepare_low

    {

engine:

binlog_prepare

innobase_xa_prepare

mysql:

trx_prepare_for_mysql

{

                1.trx_undo_set_state_at_prepare    //设置undo段的标记为TRX_UNDO_PREPARED

                2.设置事务状态为TRX_STATE_PREPARED

                3.trx_flush_log_if_needed  //将产生的redolog刷入磁盘

            }

     }

     

commit阶段:

   1.将事务产生的binlog写入文件,刷入磁盘;

   2.设置undo页的状态,置为TRX_UNDO_TO_FREETRX_UNDO_TO_PURGE;  // trx_undo_set_state_at_finish调用

   3.记录事务对应的binlog偏移,写入系统表空间; //trx_sys_update_mysql_binlog_offset调用

MYSQL_BIN_LOG::commit

    ordered_commit

   {

1.FLUSH_STAGE

        flush_cache_to_file  //  刷binlog

2.SYNC_STAGE

        sync_binlog_file    //Call fsync() to sync the file to disk.

3.COMMIT_STAGE

        ha_commit_low

        {

            binlog_commit

            innobase_commit   

                trx_commit(trx) 

                {

                    trx_write_serialisation_history(trx, mtr);  //更新binlog位点,设置undo状态

                    trx_commit_in_memory(trx, lsn); //释放锁资源,清理保存点列表,清理回滚段

                }        

        } 

    }

   

在任何情况下(机器掉电)mysqld crash或者os crash,MySQL仍然能保证数据库的一致性。数据的一致性是如何做到的哪?正是二阶段提交。

我们结合几种场景来分析下二阶段提交是如何做到的:

1.prepare阶段,redo log落盘前,mysqld crash

2.prepare阶段,redo log落盘后,binlog落盘前,mysqld crash

3.commit阶段,binlog落盘后,mysqld crash

对于第一种情况,由于redo没有落盘,毫无疑问,事务的更新肯定没有写入磁盘,数据库的一致性受影响;

对于第二种情况,这时候redo log写入完成,但binlog还未写入,事务处于TRX_STATE_PREPARED状态,这是提交还是回滚呢?

对于第三种情况,此时,redo log和binlog都已经落盘,只是undo状态没有更新,虽然redo log和binlog已经一致了,事务是否应该提交?

   

我们结合mysqld异常重启后的执行逻辑以及关键的源代码。

对于第三种情况,我们可以搜集到未提交事务的binlog event,所以需要提交

对于第二种情况,由于binlog未写入,需要通过执行回滚操作来保证数据库的一致性。

   

异常重启后,如何判断事务该提交还是回滚

1.读binlog日志,获取崩溃时没有提交的event;  //info->commit_list中含有该元素

2.若存在,则对应的事务要提交;否则需要回滚。

   

判断事务提交或回滚源码如下:

   

上面讨论了两阶段提交的基本流程,以及服务器异常crash后,mysql如何重启恢复保证binlog和数据的一致性。

简而言之,对于异常的xa事务,若binlog已落盘,则事务应该提交;binlog未落盘,则事务就应该回滚。

   

//异常重启后,回滚流程

innobase_rollback_by_xid

rollback_by_xid

trx_rollback_resurrected

    trx_rollback_active

        row_undo

        {

            //从回滚页获取undo记录

            //分析undo记录类型

            if (insert)

                row_undo_ins

            else

                row_undo_mod

        }

 

   

//异常重启后,提交流程

commit_by_xid

trx_commit_for_mysql

   

//写binlog接口

handler.cc:binlog_log_row

sql/binlog.cc:commit

mysys/my_sync:my_sync

sql/binlog.cc:sync_binlog_file

handler/ha_innodb.cc:innobase_xa_prepare

   

binlog日志文件是为了解决MySQL主从复制功能而引入的一份新日志文件,它包含了引发数据变更的事件日志集合。

从库请求主库发送 binlog 并通过日志事件还原数据写入从库,所以从库的数据来源为 binlog。

这样 MySQL 主库只需做到 binlog 与本地数据一致就可以保证主从库数据一致(暂且忽略网络传输引发的主从不一致)。

   

参考

   1、《高性能MySQL》

   2、mysql 事务提交过程

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL事务提交过程(二) 的相关文章

  • 2019年电赛之路——2015年电子设计竞赛A题任务设计

    参加19年电赛 我们奔着电源题来的 所以我们一开始要练习的题目就选定了15年的A题 因为我们找到了几个国一方案 但是只有一个方案 代码和PCB图都没有 这也是我们失误的地方 本来的路线应该是找一个成品方案 模仿着做下来 先做下来一个题目后
  • 剑指 Offer 05. 替换空格(java+python)

    请实现一个函数 把字符串 s 中的每个空格替换成 20 示例 1 输入 s We are happy 输出 We 20are 20happy 限制 0 lt s 的长度 lt 10000 java StringBuilder StringB
  • tomcat7启动报taglib标签错误

    问题描述 应用在tomcat6上发布没有问题 部署到tomcat7后报错 不识别配置的taglib标签 问题截图如下 解决方法 查询应用环境 除服务器为tomcat7外 配置的web xml 头文件为 测试头文件为
  • Arduino 自动初始化ESP8266为透传模式

    通过上篇可以把esp8266设置成透传模式 但掉电后esp8266会退出透传模式 需要重新初始化 这样arduino和esp8266结合使用时 每次重启后都要通过电脑重新设置esp8266进入透传模式 这里通过把AT指令写进arduino程
  • elasticsearch 为“非查询字段”不建索引 index store

    官方文档 index 简章翻译 文末附原文 索引index 这个参数可以控制字段应该怎样建索引 怎样查询 它有以下三个可用值 no 不把此字段添加到索引中 也就是不建索引 此字段不可查询 not analyzed 将字段的原始值放入索引中
  • python元组练习题

    Python 元组综合练习 使用python语言创建空元组 score 按学号顺序 由小到大 保存多个学生一门课程的 考试成绩 调用元组操作的常用函数实现以下功能 1 创建score 元组 其中包含10 个数值 68 87 92 100 7
  • Golang当中的定时器

    定时器 前言 定时器的基本使用 前言 在平时写代码的时候 我们经常会遇到在将来某个时间点或者间隔一段时间重复执行函数 这个时候我们就可以考虑使用定时器 本片文章主要介绍一下golang当中的几个常用的定时器 time Timer time
  • (二十六)admin-boot项目之基于注解的数据字段脱敏

    项目地址 https gitee com springzb admin boot 如果觉得不错 给个 star 简介 这是一个基础的企业级基础后端脚手架项目 主要由springboot为基础搭建 后期整合一些基础插件例如 redis xxl
  • VMware 14 安装win7x64

    所需工具 VMware17 windows镜像 windows镜像在脚本之家下载的 1 新建虚拟机 文件 gt 新建虚拟机 gt 下一步 2 选择 稍候安装操作系统 下一步 3 选择操作系统和版本 下一步 4 设置虚拟机名称和存放位置 选择
  • java动态创建xml文件

    private static void createXml String dest throws Exception DocumentBuilderFactory factory DocumentBuilderFactory newInst
  • Java中占位符的实战运用

    java中的占位符 有以下几种等等 s字符串类型的占位符 b布尔类型的占位符 d整数类型的占位符 c字符类型的占位符 我们大多情况就只用前两种 举个例子 Created by xiwen on 2021 1 14 Slf4j public
  • 常用小工具使用记录整理

    简单记录方便后续使用 1 截图软件 FSCapture exe FSCapture最新版是款适合电脑屏幕中使用的抓屏工具 FSCapture官方版集成了图像捕捉 图像浏览以及图像编辑等功能为一体 帮助用户对截取的图形进行处理操作 并且FSC

随机推荐