MYSQL事务的底层原理( 七 )


  1. redo log 占用的空间非常小存储表空间 ID、页号、偏移量以及需要更新的值所需的存储空间是很小的;
  2. redo log 是顺序写入磁盘的在执行事务的过程中 , 每执行一条语句,就可能产生若干条 redo log,这些日志是按照产生的顺序写入磁盘的 , 也就是使用顺序 IO;
redo log 的写入过程InnoDB 为了更好的进行系统崩溃恢复,把一次原子操作生成的 redo log 都放在了大小为 512 字节的块(block)中 。
为了解决磁盘速度过慢的问题而引入了 Buffer Pool 。同理,写入 redo log 时也不能直接写到磁盘上,实际上在服务器启动时就向操作系统申请了一大片称之为 redo log buffer 的连续内存空间,即:redo log 缓冲区,也可以简称:log buffer 。这片内存空间被划分成若干个连续的 redo log block,可以通过启动参数 innodb_log_buffer_size 来指定 log buffer 的大小,该启动参数的默认值为:16MB 。
向 log buffer 中写入 redo log 的过程是顺序的 , 也就是先往前边的 block 中写,当该 block 的空闲空间用完之后再往下一个 block 中写 。
redo log 刷盘时机
log buffer 什么时候会写入到磁盘呢?
  • log buffer 空间不足时 , 如果不停的往这个有限大小的 log buffer 里塞入日志,很快它就会被填满 。InnoDB 认为如果当前写入 log buffer 的 redo log 量已 经占满了 log buffer 总容量的大约一半左右,就需要把这些日志刷新到磁盘上 。
  • 事务提交时,必须要把修改这些页面对应的 redo log 刷新到磁盘 。
  • 后台有一个线程,大约每秒都会刷新一次 log buffer 中的 redo log 到磁盘 。
  • 正常关闭服务器时等等 。
undo 日志事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做 。但是偏偏有时候事务执行到一半会出现一些情况,比如:
  • 情况一:事务执行过程中可能遇到各种错误,比如服务器本身的错误 , 操作系统错误,甚至是突然断电导致的错误 。
  • 情况二:程序员可以在事务执行过程中手动输入 ROLLBACK 语句结束当前的事务的执行 。
这两种情况都会导致事务执行到一半就结束 , 但是事务执行过程中可能已经修改了很多东西,为了保证事务的原子性,需要把东西改回原先的样子 , 这个过程就称之为回滚,即:rollback,这样就可以造成这个事务看起来什么都没做,所以符合原子性要求 。
每当要对一条记录做改动时,都需要把回滚时所需的东西都给记下来 。
比方说:
  • 插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉 。
  • 删除了一条记录 , 至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中 。
  • 修改了一条记录 , 至少要把修改这条记录前的旧值都记录下来 , 这样之后回滚时再把这条记录更新为旧值 。
这些为了回滚而记录的这些东西称之为撤销日志,即:undo log 。这里需要注意的一点是,由于查询操作并不会修改任何用户记录 , 所以在查询操作执行时,并不需要记录相应的 undo log 。
undo 日志的格式
为了实现事务的原子性,InnoDB 存储引擎在实际进行增、删、改一条记录时 , 都需要先把对应的 undo 日志记下来 。一般每对一条记录做一次改动,就对应着一条 undo 日志,但在某些更新记录的操作中 , 也可能会对应着 2 条 undo 日志 。
一个事务在执行过程中可能新增、删除、更新若干条记录,也就是说需要记录很多条对应的 undo 日志,这些 undo 日志会被从 0 开始编号,也就是说根据生成的顺序分别被称为第 0 号 undo 日志、第 1 号 undo 日志、...、第 n 号 undo 日志等,这个编号也被称之为 undo no 。
这些 undo 日志是被记录到类型为 FIL_PAGE_UNDO_LOG 的页面中 。这些页面可以从系统表空间中分配,也可以从一种专门存放 undo 日志的表空间 , 也就是所谓的 undo tablespace 中分配 。




推荐阅读