MySQL InnnoDB 存储引擎事务

事务(Transaction)是数据库区别于文件系统的重要特性之一。事务会把数据库从一种一致状态转换为另一种一致状态。
事务可由一条非常简单的 SQL 语句组成,也可以由一组复杂的 SQL 语句组成。事务是访问并更新数据库中各种数据项的一个程序执行单元。在事务中的操作,要么都做修改,要么都不做。

事务的概念

InnoDB 存储引擎中的事务完全符合 ACID 的特性:

  • 原子性(Atomicity)
    原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,才算整个事务成功。事务中任何一个 SQL 语句执行失败,已经执行成功的 SQL 语句也必须撤销,数据库状态应该退回到执行事务前的状态。

  • 一致性(Consistency)
    一致性指事务将数据库从一种状态转变为下一种一致的状态。在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏。

  • 隔离性(Isolation)
    隔离性又叫做 并发控制(concurrency control)可串行化(serializability)锁(locking)等。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前对其他事务都不可见,通常这使用锁来实现。由定义可见,一般用于出发数据的的并发请求。

  • 持久性(durability)
    事务一旦提交,其结果就是永久性的。即使发生宕机等故障,数据库也能将数据恢复。但是只能从事务本身的角度来保证结果的永久性,一些外部原因的故障导致的数据丢失是无法保障的。因此持久性保证事务系统的高可靠性(High Reliability),而不是高可用性(High Availability)

事务的实现

事务的隔离性由锁来实现,关于 InnoDB 存储引擎中的锁,可以参考本人之前的一篇文章
原子性、一致性、持久性通过数据库的 redo log 和 undo log 来完成。redo log 称为重做日志,用来保证事务的原子性和持久性。undo log 用来保证事务的一致性。

redo

redo log 用来实现事务的持久性,记录的是对于每个页的修改
其由两部分组成:

  • 内存中的重做日志缓冲(redo log buffer),因为是存在于内存中,其是易失的;
  • 重做日志文件(redo log file),其是持久的

InnoDB 存储引擎通过 Force Log at Commit 机制来实现事务的持久性,即当事务提交(COMMIT)使,必须先讲该事务的所有日志写入到重做日志文件进行持久化,待事务的 COMMIT 操作完成才算完成。为了确保每次日志都写入重做日志文件,在每次将重做日志缓冲写入重做日志文件后,InnoDB 存储引擎都需要调用一次 fsync 操作(确保重做日志从文件系统缓存写入到磁盘)。

与 binlog 的区别

接触过 MySQL 的同学应该多少都会了解 binlog,会发现 binlog 与 redo log 非常相似,都是记录了对于数据操作的日志,为什么还要引入 redo log?binlog的两个重要使用场景:

  1. MySQL 主从复制
  2. 数据恢复

但是两者是存在非常大的区别的:

  • redo log 是在 InnoDB 存储引擎层产生,binlog 是在 MySQL 数据库的上层产生,不仅仅针对 InnoDB 存储引擎
  • 内容形式不同。binlog 是一种逻辑日志,记录的是对应的 SQL 语句或行的内容;redo log 是物理格式日志,记录的是对于每个页(InnoDB 数据的存储格式)的修改
  • 写入磁盘的时间点不同。binlog 只在事务提交完成后进行一次写入;redo log 在事务进行中不断地被写入。
  • redo log 空间是固定的,可重用;binlog 是追加写,当前文件写完之后会开启一个新文件继续写。

InnoDB 存储引擎在启动时不管上次数据库运行时是否正常关闭,都会尝试进行恢复操作。redo log 记录的是物理日志,恢复速度比 binlog 要快很多,而且InnoDB 恢复还进行了一定程度的优化-顺序读取及并行应用redo log。

group commit

事务的两阶段提交

  1. 修改内存中事务对应的信息,并且将日志写入重做日志缓冲
  2. 调用 fsync 确保日志都从重做日志缓冲写入磁盘

若事务为非只读事务,则每次事务提交时需要进行一次 fsync 操作,以此保证重做日志已经写入磁盘。

因为磁盘的 fsync 性能时有限的,即上面的第二阶段是个较慢的过程。但是当有事务进行第二阶段提交时,其他事务可以进行第一阶段的提交,正在提交的事务完成提交操作后,再次进行第二阶段,即 group commit ,一次 fsync 可以刷新确保多个事务日志被写入文件。

但是开启 binlog 之后,group commit 功能就会失效。这是因为开启 binlog 之后,需要保证binlog 和 redo log 的一致性,二者之间使用了两阶段事务,步骤如下:

  1. 事务提交时 InnoDB 存储引擎进行 prepare 操作
  2. MySQL 数据库上层写入 binlog
  3. InnoDB 存储引擎将日志写入 redo log
    1. 写入redo log 缓冲
    2. 调用 fsync
      开启 binlog 后 InnoDB 存储引擎的提交过程.png

      为了保证 binlog 的写入顺序和 事务提交顺序一致,MySQL 内部使用了 prepare_commit_mutex 锁,启用该锁后,步骤3.1 不可以在其他事务执行 3.2 时进行,从而导致了 group commit 失效。

MySQL 5.6 采用 Binary Log Group Commit(BLGC) 来提高日志的写入性能:
在 MySQL 数据库上层进行提交时首先按顺序将其放入一个队列中,队列中的第一个事务称为 leader,其他事务称为 follower,leader 控制着 follower 的行为。

  1. Flush 阶段,将每个事务的 binlog 写入内存中
  2. Sync 阶段,内存中的 binlog 刷新到磁盘(如果队列中有多个事务,一次 fsync 操作就完成了多个 binlog 的写入)
  3. Commit 阶段,leader 根据顺序调用存储引擎层事务的提交,InnoDB 可以继续使用 group commit

undo

undo log 用于将数据回滚到修改之前的样子,因为回滚做的事情实际上是与之前相反的工作。所以,对于 INSERT ,undo log 会对应一个 DELETE 记录;对于 DELETE,画丶do log 对应一个 INSERT;对于 UPDATE,undo log 对应一个相反的 UPDATE。
undo log 另一个作用是 MVCC,当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过 undo 读取之前的行版本信息,从而实现 一致性非锁定读。

undo 存储管理

InnoDB 存储引擎对 undo 的管理采用段(segment)的方式,rollback segment 称为回滚段,每个回滚段记录了 1024 个 undo log segment。

在 InnoDB 存储引擎中,undo log 分为 insert undo logupdate undo log

  • insert undo log 是指在 insert 操作中产生的 undo log,因为 insert 操作只对本事务自身可见,故该 undo log 可以在事务提交后直接删除。
  • update undo log 记录的是对 delete 和 update 操作产生的 undo log。该 undo log 可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除,提交时放入 undo log 链表,等待 purge 线程进行最后的删除。

事务提交后并不能马上删除 undo log 及 undo log 所在的页。因为可能还有其他事务需要通过 undo log 来得到行记录之前的版本。事务提交时将 undo log 放入一个链表中,是否可以最终删除 undo log 及 undo log 所在页由 purge 线程来判断。并且提交事务时,还会判断 undo log 页是否可以重用,如果可以重用,则会分配给后面的事务。

purge

purge 操作用于最终完成 deleteupdate 操作。

InnoDB 存储引擎有一个 history 列表,根据事务提交的顺序,将 undo log 进行链接。InnoDB 存储引擎先从 history list 中找 undo log,然后再从 undo page 中找 undo log,避免大量的随机读取操作,从而提高 purge 的效率。

redo log 用来保证事务的持久性,undo log 用来帮助事务回滚以及 MVCC 的功能。redo log 基本上都是顺序写的,在数据运行时不需要对 redo log 的文件进行读取操作,而 undo log 是需要进行随机读取的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容