关于mysql:MySQL-是如何实现-ACID-的

52次阅读

共计 2154 个字符,预计需要花费 6 分钟才能阅读完成。

咱们都晓得,事务具备 ACID 四个个性——原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。但你晓得 MySQL 是通过什么技术手段来实现的吗?

ACID 简介

先来简略回顾一下 ACID 的定义:

原子性 :事务作为一个整体被执行,蕴含在其中的对数据库的操作要么全副被执行,要么都不执行。

一致性 :事务开始前和事务完结后,数据库的完整性没有被毁坏。即写入的数据必须完全符合所有的预设束缚、触发器、级联回滚等。

隔离性 :多个事务并发执行时,一个事务的执行不应影响其余事务的执行。

持久性 :已被提交的事务对数据库的批改应该永恒保留在数据库中。即便零碎挂了,数据也不会丢。

咱们依照:持久性 -> 原子性 -> 隔离性 -> 一致性 的程序来探讨。

PS:本文基于 InnoDB

持久性

咱们晓得程序修改数据的时候,是先将数据从磁盘加载到内存,而后批改完再由内存写回磁盘。长久化其实就是将内存里的数据写入磁盘。因而,持久性的要害就在于如何保证数据能够由内存顺利写入磁盘。

咱们有以下几个计划:

计划一:

  1. 加载数据到内存
  2. 批改内存
  3. 而后写回磁盘
  4. 提交事务

计划二:

  1. 加载数据到内存
  2. 批改内存
  3. 提交事务
  4. 后盾写回磁盘

第一种计划,靠谱是靠谱,但性能太低,会重大连累 MySQL 的吞吐量。

第二种计划尽管性能上来了,但如果在第四步时宕机了,而零碎认为事务已提交,这时候就会失落数据了。

那怎么办呢?MySQL 给出的计划是 WAL(Write Ahead Log)机制。WAL 翻译过去就是先写日志的意思。这个日志就是 redo log。具体做法是:

  1. 加载数据到内存
  2. 批改内存
  3. 写入 redo log
  4. 提交事务
  5. 后盾写回磁盘

如果第五步时零碎宕机,也能够通过 redo log 来复原。

你可能有疑难:写入 redo log 不也有磁盘 I/O 吗?这不是脱了那啥再那啥,多此一举吗?写 redo log 和写表的区别就在于随机写和程序写。MySQL 的表数据是随机存储在磁盘中的,而 redo log 是一块固定大小的间断空间。而磁盘程序写入要比随机写入快几个数量级。

因而,这种计划即保障了数据的平安,性能上也可能承受。

原子性

如果一个事务做了如下操作:

  1. 插入一条数据 insert into user values(‘1′,’ 小刘 ’,’18’)
  2. 更新一条数据 update user set name = ‘ 小水 ’ where id = 2
  3. 删除一条数据 delete from user where id = 3

依据原子性的规定,这三个操作要么都胜利,要么都失败。那么问题就来了,如何保障 3 失败的状况下,让 1,2 也回退呢?

答案就是 undo log。

每个事务操作(增删改)都会记录一条与之对应的 undo log:

  1. insert 记录插入的主键,回滚则依据该主键删除记录
  2. update 记录记录主键和被批改列的以后值,回滚则依据主键和之前的值笼罩
  3. delete 为记录增加删除标记,即 MySQL 外部的逻辑删除,回滚依据主键复原

隔离性

数据库事务有四种隔离级别,不同的级别可能会呈现各种各样的问题(脏读、幻读、不可反复读),关系如下:

隔离级别 脏读 不可反复读 幻读
读未提交(Read uncommitted) 可能 可能 可能
读已提交(Read committed) 不可能 可能 可能
可反复读(Repeatable read) 不可能 不可能 可能
可串行化(Serializable) 不可能 不可能 不可能

MySQL 中 RR 级别曾经解决了幻读问题。

并发的状况才须要隔离,而并发有三种组合:

  1. 读读
  2. 读写
  3. 写写

「读读」的状况,不须要隔离;「读写」通过 MVCC 隔离;「写写」只能通过锁来隔离。

MVCC(Multi Version Concurrency Control,多版本并发管制)作用于 RC 和 RR 级别。能够为事务中的读操作创立一个快照(Readview),从而来防止被其余事务烦扰。

RC 级别下,一个事务中的每次(同参数)读都会创立一个 Readview。

RR 级别下,一个事务中只在第一次读时创立 Readview,前面再次读,依然读取该 Readview。

「写写」的状况通过三种锁来实现隔离:Record Lock、Gap Lock 和 Next Key Lock(前两者的组合)。

Record Lock 锁住一条数据,从而使其余事务无奈批改和删除;Gap Lock 锁住一个范畴,从而使其余事务不能在该区间插入数据;Next Key Lock 锁住具体数据和区间,从而使其余事务无奈更新、删除和在该区间插入数据。

MVCC + 锁 使得 MySQL 在 RR 级别防止了幻读问题。

一致性

很多人聊到一致性,很喜爱拿转账的业务举例,但这显著是原子性的领域——A 账户扣钱,B 账户加钱,两个 Update 操作,要么都胜利,要么都失败。

一致性更偏重是,数据的完整性:主外键束缚、惟一索引、列残缺等。MySQL 中保障一致性次要靠 CR(Crash Recovery)和 DWB(Doublewrite Buffer)来保障的。

这两个个性比较复杂,一篇文章基本讲不完,如果你感兴趣能够去看官网文档,或者留言通知我,我来安顿。

最初

一致性是一个比拟非凡的存在,它和原子性、隔离性有一层「你中有我,我中有你」的暧昧关系。比方转账的业务场景,如果说它属于一致性的领域,也可能说得通,能够叫「用户自定义一致性」;另外,隔离性使得事务之间互不影响的最终成果也是保障了数据的统一。

正文完
 0