mysql事务prepare_mysql之 事务prepare 与 commit 阶段分析

打开binlog选项后,执行事务提交命令时,就会进入两阶段提交模式。两阶段提交分为prepare阶段和commit两个阶段。流程如下 :这里面涉及到两个重要的参数:innodb_flush_log_at_trx_commit和sync_binlog,参数可以设置不同的值,具体可以查看mysql的帮助手册。我这里设置的是双一模式(innodb_flush_log_at_trx_commit=1,sync_binlog=1),不同的模式区别在于,写文件调用write和落盘fsync调用的频率不同,所导致的后果是mysqld 或 os crash后,不严格的设置可能会丢失事务的更新。双一模式是最严格的模式,这种设置情况下,单机在任何情况下不会丢失事务更新。

prepare阶段:

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

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

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调用

下面这部分是我抽象出来的源码调用部分,大家可以通过单步调试方式,在关键函数中设置断点,来详细了解这个过程。

===========

prepare阶段

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阶段

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也有可能出现问题,另外若机器掉电,mysqld也会同样挂掉。但是即使这样,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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL XA事务是一种分布式事务处理方式,它允许多个独立的事务同时访问多个数据库,并将它们作为一个全局事务进行处理,从而保证了数据的一致性和完整性。 在MySQL 5.7中,XA事务的实现基于两个重要的组件:XA接口和InnoDB存储引擎。XA接口提供了一组标准API,使得应用程序可以以统一的方式与分布式事务协调器进行通信,而InnoDB存储引擎则提供了具体的XA事务实现。 要使用MySQL XA事务,需要确保以下几点: 1. 数据库支持XA协议,如MySQL 5.7及以上版本。 2. 数据库引擎支持XA事务,如InnoDB存储引擎。 3. 应用程序使用XA接口与协调器进行通信。 4. 执行XA事务的数据库必须在同一个XA事务中注册。 在使用MySQL XA事务时,需要对事务进行以下基本操作: 1. 准备(prepare):在分布式事务中,每个数据库都会先执行准备操作,以确保所有数据库都可以成功执行事务。 2. 提交(commit):当所有数据库都准备好时,可以执行提交操作,将分布式事务提交到所有数据库。 3. 回滚(rollback):如果任意一个数据库无法完成准备或提交操作,则需要执行回滚操作,以确保所有数据库都回到事务开始前的状态。 总的来说,MySQL XA事务是一种非常强大的分布式事务处理方式,可以实现多个独立的事务同时访问多个数据库,并将它们作为一个全局事务进行处理,从而保证了数据的一致性和完整性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值