MySQL ACID的底层实现

MySQL事务实现

BEGIN TRANSACTION -- 开启事务

COMMIT -- 将执行结果提交

ROLLBACK -- 出现异常需要回滚

ACID

A(Atomicity):原子性。原子性是指事务是一个不可分割的工作单位,事务中操作要么都发生,要么都不发生。

C(Consistency):一致性。事务前后的数据必须保持一致性。

I(Isolation):隔离性。事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务所干扰,多个并发事务之间要相互隔离。保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR,RR的实现主要基于锁机制、数据的隐藏列、undo log和类next-key lock机制

D(Durability):持久性。持久性是指一个事务一旦被提交,它对数据库中的数据改变是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

事务的实现

MySQL中有undo log(用于回滚)和redo log(用于数据写入)

事务的原子性是通过undolog来实现的。
事务的持久性性是通过redolog来实现的。
事务的隔离性是通过(读写锁+MVCC)来实现的。
事务的一致性是通过原子性,持久性,隔离性来实现的。

原子性操作(undo log 实现回滚)

undo log记录的都是执行数据变更操作的逆向操作,在进行回滚的操作时候,可以从undo log文件中读取出来,然后执行,就可以将数据恢复回来。

MySQL的日志有很多种,如二进制日志、错误日志、查询日志、慢查询日志等,此外InnoDB存储引擎还提供了两种事务日志:
redo log(重做日志)和undo log(回滚日志)。其中redo log用于保证事务持久性;
undo log则是事务原子性和隔离性实现的基础。

每条数据变更的时候都伴随一条undo log记录生成,并且回滚日志必须先于数据持久化到磁盘。
undo log属于逻辑日志,它记录的是sql执行相关的信息。
所谓的回滚就是根据回滚日志做逆向操作,比如 delete 的逆向操作为 insert ,insert的逆向操作为delete,update的逆向为update等。

根据 undo log 进行回滚:
为了做到同时成功或者失败,当系统发生错误或者执行 rollback 操作时需要根据 undo log 进行回滚。
回滚操作就是要还原到原来的状态,undo log记录了数据被修改前的信息以及新增和被删除的数据信息,根据undo log生成回滚语句,比如:

  • 如果在回滚日志里有新增数据记录,则生成删除该条的语句
  • 如果在回滚日志里有删除数据记录,则生成生成该条的语句
  • 如果在回滚日志里有修改数据记录,则生成修改到原先数据的语句

持久性的实现(redo log,故障后恢复)

读数据:会首先从缓冲池中读取,如果缓冲池中没有,则从磁盘读取在放入缓冲池;
写数据:会首先写入缓冲池,缓冲池中的数据会定期同步到磁盘中(会产生脏读);

于是 redo log就派上用场了。
既然redo log也需要存储,也涉及磁盘IO为啥还用它?
1.redo log 的存储是顺序存储,而缓存同步是随机操作。
2.缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。

redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,
从而满足了持久性要求。

既然redo log也需要在事务提交时将日志写入磁盘,为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:
a.刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。
b.刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分,无效IO大大减少。

redo log 与binlog的区别:
a.作用不同:redo log是用于crash recovery的,保证MySQL宕机也不会影响持久性;binlog是用于point-in-time recovery的,保证服务器可以基于时间点恢复数据,此外binlog还用于主从复制。
b.层次不同:redo log是InnoDB存储引擎实现的,而binlog是MySQL的服务器层(可以参考文章前面对MySQL逻辑架构的介绍)实现的,同时支持InnoDB和其他存储引擎。
c.内容不同:redo log是物理日志,内容基于磁盘的Page;binlog的内容是二进制的,根据binlog_format参数的不同,可能基于sql语句、基于数据本身或者二者的混合。
d.写入时机不同:binlog在事务提交时写入;redo log的写入时机相对多元:
前面曾提到:当事务提交时会调用fsync对redo log进行刷盘;这是默认情况下的策略,修改innodb_flush_log_at_trx_commit参数可以改变该策略,但事务的持久性将无法保证。
除了事务提交时,还有其他刷盘时机:如master thread每秒刷盘一次redo log等,这样的好处是不一定要等到commit时刷盘,commit速度大大加快。

隔离性的实现(锁以及MVCC)

隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
严格的隔离性,对应了事务隔离级别中的Serializable (可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。

Mysql隔离级别有以下四种(级别由低到高):READUNCOMMITED(未提交读)、READCOMMITED(提交读)、REPEATABLEREAD(可重复读)、SERIALIZABLE (可重复读)。

隔离级别 脏读 可重复读 幻读
READUNCOMMITED 可能 可能 可能
READCOMMITED 不可能 可能 可能
REPEATABLEREAD 不可能 不可能 可能
SERIALIZABLE 不可能 不可能 不可能

(一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性。
(一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性。

脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。

MVCC

MVCC最大的优点是读不加锁,因此读写不冲突,并发性能好。InnoDB实现MVCC,多个版本的数据可以共存,
主要是依靠数据的隐藏列(也可以称之为标记位)和undo log。其中数据的隐藏列包括了该行数据的版本号、删除时间、指向undo log的指针等等;
当读取数据时,MySQL可以通过隐藏列判断是否需要回滚并找到回滚需要的undo log,从而实现MVCC;

InnoDB实现的RR通过next-key lock机制避免了幻读现象。

next-key lock是行锁的一种,实现相当于record lock(记录锁) + gap lock(间隙锁);其特点是不仅会锁住记录本身(record lock的功能),
还会锁定一个范围(gap lock的功能)。
当然,这里我们讨论的是不加锁读:此时的next-key lock并不是真的加锁,只是为读取的数据增加了标记(标记内容包括数据的版本号等);
准确起见姑且称之为类next-key lock机制。

一致性的实现

数据库总是从一个一致性的状态转移到另一个一致性的状态。

实现一致性的措施包括:
保证原子性、持久性和隔离性,如果这些特性无法保证,事务的一致性也无法保证
数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等
应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致

参考文献

深入学习MySQL事务:ACID特性的实现原理
MySQL 中 ACID 底层内部实现原理详解(重点推荐)
[玩转MySQL之九]MySQL实现ACID机制之持久性

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

推荐阅读更多精彩内容

  • 我们都知道事务有4种特性:原子性、一致性、隔离性和持久性,在事务中的操作,要么全部执行,要么全部不做,这就是事务的...
    pjmike阅读 31,842评论 5 36
  • 写在前面 本文是对于网上各个对redo和undo log日志解析的总结,参考文章列表在最后。 事务的4大特性:原子...
    吕信阅读 8,285评论 0 11
  • 转载:https://www.cnblogs.com/superchong/p/10847966.html逻辑架构...
    AllDb阅读 188评论 0 0
  • 本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo Log Undo Log 是为了实...
    胖虎大哥阅读 2,251评论 1 3
  • 不知道为什么?似乎整个世界都弥漫着一股焦燥不安的气息,好像每个人都迫切于于把自己从枷锁中解放出来,也不知道有没有想...
    徐途阅读 156评论 0 0