MySQL事务的提交过程

68次阅读
没有评论

共计 3420 个字符,预计需要花费 9 分钟才能阅读完成。

本篇内容介绍了“MySQL 事务的提交过程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

MySQL 事务提交过程
开启 binlog 后事务提交流程会变成两阶段提交,这里的两阶段提交并不涉及分布式事务,当然 mysql 把它称之为内部 xa 事务(Distributed Transactions),与之对应的还有一个外部 xa 事务。

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

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

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

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

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

数据库版本:5.6.16

操作系统版本:CentOS 6.5

配置文件参数:
log-bin=/my/log/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;

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_FREE 或 TRX_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 与本地数据一致就可以保证主从库数据一致(暂且忽略网络传输引发的主从不一致)。

“MySQL 事务的提交过程”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-28发表,共计3420字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)