InnoDB如何保证事务的四大特性

咱们知道事务有四大特性,原子性、一致性、隔离性与持久性。那么MySQL中的事务是如何保证这些特性的呢?html

MySQL的存储引擎InnoDB使用重作日志保证一致性与持久性,回滚日志保证原子性,使用各类锁来保证隔离性。数据库

重作日志(redo log)

防止在发生故障的时间点,尚有脏页未写入磁盘,在重启MySQL服务的时候,根据重作日志进行重作,从而达到事务的持久性这一特性。 重作日志由两部分组成,一是内存中的重作日志缓存,其是易失的;二是重作日志文件,其是持久的。重作日志是物理日志,记录的是对于每一个页的修改。事务开始后Innodb存储引擎先将重作日志写入缓存(innodb_log_buffer)中。而后会经过如下三种方式将innodb日志缓冲区的日志刷新到磁盘。缓存

  1. Master Thread每秒一次执行刷新Innodb_log_buffer到重作日志文件。
  2. 每一个事务提交时会将重作日志刷新到重作日志文件。
  3. 当重作日志缓存可用空间少于一半时,重作日志缓存被刷新到重作日志文件

当事务提交时,必须先将该事务的全部日志写入到重作日志文件进行持久化。为了确保每第二天志都写入重作日志文件,在每次将日志缓冲写入重作日志文件后,InnoDB存储引擎都须要调用一次fsync操做。但这也不是绝对的。用户能够经过修改innodb_flush_log_at_trx_commoit参数来控制重作日志刷新到磁盘的策略。参数默认值为1,表示事务提交时必须调用一次fsync操做。0表示事务提交时,重作日志缓存并不当即写入重作日志文件,而是随着Master Thread的间隔进行fsync操做。2表示事务提交时将重作日志写入重作日志文件,但仅写入文件系统的缓存中,不进行fsync操做。 在InnoDB存储引擎中。重作日志都是以512字节进行存储的,称之为重作日志块,与磁盘扇区大小一致,这意味着重作日志的写入能够保证原子性,不须要doublewrite技术。并发

回滚日志(undo log)

事务发生异常须要回滚,这时就须要回滚日志。回滚日志不一样于重作日志,它是逻辑日志,对数据库的修改都逻辑的取消了。当事务回滚时,它实际上作的是与先前相反的工做。对于每一个INSERT,InnoDB存储引擎都会完成一个DELETE;对于每一个UPDATE,InnoDB存储引擎都会执行一个相反的UPDATE。线程

事务开始会依照当前版本生成回滚日志,事务也可使用回滚日志实现多版本并发控制来保证事务的隔离性。事务提交后并不会立刻删除回滚日志,由于可能还有其它事务须要经过回滚日志来获得版本信息。因此事务提交时将回滚日志放入链表中,是否能够删除由purge线程判断。日志

回到刚刚讲的重作日志,未提交的事务和回滚了的事务也会产生重作日志。InnoDB存储引擎会重作全部事务包括未提交的事务和回滚了的事务,而后经过回滚日志回滚那些未提交的事务。使用这种策略须要回滚日志在重作日志以前写入磁盘,使得持久化变得复杂起来。为了下降复杂度,InnoDB存储引擎将回滚日志做数据,记录回滚日志的操做也会记录到重作日志中。这样回滚日志就能够像数据同样缓存起来,而不用在重写日志以前写入磁盘了。htm

Undo + Redo事务的简化过程

假设有A、B两个数据,值分别为1,2。blog

  1. 事务开始
  2. 记录A=1到undo log
  3. 修改A=3
  4. 记录A=3到redo log
  5. 记录B=2到undo log
  6. 修改B=4
  7. 记录B=4到redo log
  8. 将redo log写入磁盘
  9. 事务提交

二进制日志(binlog)

在MySQL数据库中还有一种二进制日志,其用来基于时间点的还原及主从复制。从表面上来看其和重作日志很是类似,都是记录了对于数据库操做的日志。可是,从本质上来看有着很是大的不一样。 首先重作日志是在InnoDB存储引擎层产生的,而二进制日志是在MySQL数据库的上层产生的。其次,两种日志记录的内容形式不一样。二进制日志是一种逻辑日志,其记录的是对应的SQL语句。而重作日志是物理日志,记录的是每一个页的修改。此外,两种日志记录写入磁盘的时间点不一样,二进制日志只在事务提交完成后进行一次写入,重作日志在事务进行时不断地写入。事务


@COPY内存

《MySQL技术内幕:InnoDB存储引擎》

MySQL中的重作日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简单总结

MySQL数据库InnoDB存储引擎Log漫游

相关文章
相关标签/搜索