Mysql中事务及其实现

Abstract: 通过本文可以了解到Mysql中事务的特性以及保证事务的机制、mysql的常见日志文件、 两阶段提交。

事务

含义

   数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元);

特性

  ACID,及原子性、一致性、隔离性、持久性。
A: 事务是不可分割的一部分,要么全执行、要么全不执行。
C: 事务总是从一种一致性状态转换成另一种一致性状态,事务的完整性约束不会被破坏。
I: 每个事务的操作,不会收另一个事务的影响。
D: 事务一旦提交,结果就是持久性的,不会被回滚。

实现机制

  隔离性通过锁实现,原子性、持久性通过数据库的redo和undo日志来完成,一致性(包括主从复制)通过事务两阶段提交来完成。

实现机制在以下进行详细说明。

日志

redo log

  作用:保证事务的持久性。redo_log记录事务执行之后的状态,用来恢复事务执行之后没有写入到data file的数据。防止在宕机时内存中仍有脏页未写入磁盘,在重启mysql服务的时候,可以根据redo_log日志重做,保证事务的一致性。
  内容:物理格式的日志,记录数据物理页面修改的信息。
  什么时候产生:事务开始的时候就会产生redo_log,redo_log的落盘不是随着事务提交的时候才进行,而是在事务执行过程中写入redo_log_file。
  什么时候释放:在对应事务的脏页写入磁盘的时候,redo_log的使命完成,占用的空间就可以被覆盖。
  关于redo_log写盘:在事务开始之后逐步写盘的。在实现上依靠innodb_log_buffer,默认大小为8M。innodb会将redo_log写入缓冲区中,然后以三种方式将缓冲区的日志刷新到磁盘。第一是master thread会在每秒一次将innodb_log_buffer中的日志文件刷新到磁盘的重做日志文件中。第二是在事务提交之后会将重做日志文件刷新到重做日志文件中。第三是重做日志缓存可用空间少于一半时,将重做日志缓存刷新到重做日志文件中。因此,重做日志的落盘并不是在事务提交之后才进行,而是在事务开始之后逐步开始,这也解释了为什么大事务提交的时间是很短暂的。

undo log

  作用:保证事务的原子性,保存事务发生之前数据的另一个版本,可以用于回滚。同时也提供了MVCC机制下的读。
  内容:逻辑格式的日志,仅仅将数据从逻辑上回复之前的状态,可以认为是一系列的sql语句。
  什么时候产生:事务开始之前产生,将当前事务版本生成undo_log,同时也会生成redo_log保证undo_log的可靠性。
  什么时候释放:在事务提交之后,undo_log并不会立刻被清除,而是加入带清理的链表,由purge线程判断其他事务是否在使用undo段中表的上一个数据版本的记录来判断是否可以清楚undo_log的日志空间。
  其他:undo是在事务开始之前保存被修改数据的当前版本,在产生undo日志的时候也会生成类似保护事务持久化机制的redo日志。

binlog

  作用:用于主从复制,从库利用主库的binlog进行重播,实现主从同步。提供基于数据库时间节点的还原。
  内容:逻辑格式的文件,可以看作执行过事务中的sql语句。
  什么时候产生:在事务提交的时候一次性将事务中的sql语句按一定格式记录到binlog中。
  什么时候释放:默认由expire_logs_days参数配置,在生成事件超过一定的天数之后会被自动删除。
  bin_log和redo_log:一、作用不同,redo是保持事务持久性,在事务层面;binlog是作为还原的功能,在数据库层面。二、内容不同,redo是物理日志是数据页面修改之后的物理记录,binlog是逻辑日志,可以认为是一系列的sql语句。另外,日志产生的时间,释放的时间,释放之后的清理机制都不同。
  另外,redo和binlog的写入顺序为了保证主从复制的一致性(包括binlog基于时间点还原的情况),是需要严格一致的。mysql通过两阶段提交来保证事务的一致性,也就是redo和binlog的一致性。理论上是先写redo再写binlog,两个日志都成功刷入磁盘,事务才整整完成。

事务的提交过程

两阶段事务提交

当有数据修改时,会先将修改redo log cache和binlog cache然后在刷入到磁盘形成redo log file,当redo log file全都刷入到磁盘时(prepare 状态)和提交成功后才能将binlog cache刷入磁盘,当binlog全部刷新到磁盘后会记录一个xid,然后在relo log file上打上commit标志(commit阶段)。

两阶段事务提交原理

  1. perpare阶段 写入redo日志
    (1)设置undo state=TRX_UNDO_PREPARED;
    (2)刷事务更新产生的redo日志;
  2. commit阶段 写入binlog日志
    (1)将事务产生的binlog写入文件,刷入磁盘;
    (2)设置undo页的状态,置为TRX_UNDO_TO_FREE或TRX_UNDO_TO_PURGE; //标记可以清理回滚段
    (3)记录事务对应的binlog偏移,写入系统表空间。
    ps: redo log的提交分为prepare和commit两个阶段,所以称之为两阶段提交

为什么要有两阶段提交

  MySQL在修改数据时,MySQL是先从磁盘中将数据copy到内存,然后再将内存中的数据进行修改,并记录redo log buffer 然后在通过系统调用将事务日志写入磁盘redo log file 最后最后事务提交后将内存中修改后的数据在开始写入磁盘中。

  1. 当只有redo log,binlog失效时,会导致主库可以通过redo log来重做,而从库因为没有及时获取到binlog而不能进行回放,导致主从数据不一致。
  2. 当只有binlog,redo log失效时会导致在主宕机时不能根据redo log重做,而从导致主从数据不一致。

而两阶段提交,就解决这个问题,crash recovery 时:
如果 redo log 已经 commit,那毫不犹豫的,把事务提交
如果 redo log 处于 prepare,则去判断事务对应的 binlog 是不是完整的。是,则把事务提交;否,则事务回滚。两阶段提交,其实是为了保证 redo log 和 binlog 的逻辑一致性。

恢复原理

扫描最后一个Binlog文件,提取其中的Xid_log_event重做检查点以后的redo日志,读取事务的undo段信息,搜集处于prepare阶段的事务链表,将事务的xid与binlog中的xid对比,若存在,则提交,否则就回滚。

恢复过程

1.在prepare阶段carsh
因为事务还没有提交,binlog还没有写入磁盘,该事务会直接rollback.
2.事务在将binlog cache写入磁盘的时候crash
因为该事务还没有全部写入磁盘,故此时xid不会写入到binlog,会认为该事务并没有提交,所以会将该事务回滚。
3.事务已经全部刷新到磁盘,但在引擎层还没有commit
因为在binlog中已经有该事务的xid,所以会将该事务在引擎层提交,然后将redo log checkpoint点之后的事务进行重做。

————————————————

Reference

hMySQL中的几种日志了解
mysql 事务提交过程
Mysql事务与两阶段提交
mysql之两阶段提交

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值