MySQL 数据库隔离级别 脏读 VS 不可重读读 VS 幻读 VS 可串行化

所在文集:数据库


本文的内容参考了:

本文会涉及到数据库的锁,请先参见:MySQL InnoDB 锁 学习笔记

数据库隔离级别

用于处理 多事务并发 的情况。

InnoDB 对四种类型都支持:

  • READ_UNCOMMITTED:读取未提交。这是并发最高,一致性最差的隔离级别。
  • READ_COMMITTED(RC):读提交。这是互联网最常用的隔离级别。
  • REPEATABLE_READ(RR):重复读。
  • SERIALIZABLE:串行化。这是一致性最好的,但并发性最差的隔离级别。

不同事务的隔离级别,实际上是一致性与并发性的一个权衡与折衷。
InnoDB 使用不同的锁策略来实现不同的隔离级别。

Read UnCommitted 读取未提交内容

InnoDB 实现方式:select 语句不加锁。

导致出现脏读:
A 事务读取了 B 事务 尚未提交 的数据并在此基础上操作,而 B 事务回滚,则 A 事务读到的数据为脏数据。例如:

A: start transaction
  B: start transaction
  B: update account set balance = 50 where id  = 1
A: select balance from account where id  = 1
  B: rollback
A: update account set balance = 50 + 100 where id  = 1
A: commit
  • B 事务读取账户余额 100 块,取钱,将余额修改为 50 块,但并没有提交。
  • A 事务读取了 尚未提交 的数据,认为余额是 50 块。
  • B 事务回滚。
  • A 事务存钱 100 块,将余额计算为 50 + 100 = 150 块,此为脏数据,实际余额应该为 200 块。

Read Committed(RC)读取提交内容

  • 这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)
  • 它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变

InnoDB 实现方式:

  • 普通的 select 使用快照读(snapshot read),这是一种不加锁的一致性读。
  • 加锁的 selectupdatedelete 等语句,除了在外键约束检查以及重复键检查时会封锁区间,其他时刻都只使用记录锁;

导致出现不可重复读:
意味着我们在同一个事务中执行完全相同的 select 语句时可能看到不一样的结果。
A 事务重复读取前面读取过的数据,
发现数据变化了
,即被其他事务 B 修改并提交过了。例如:

A: start transaction
  B: start transaction
A: select balance from account where id  = 1
  B: update account set balance = 50 where id  = 1
  B: commit
A: select balance from account where id  = 1
A: commit
  • A 事务第一次读取余额 100 块。
  • B 事务读取账户余额 100 块,取钱,将余额修改为 50 块,并提交。
  • A 事务第二次读取余额,变成了 50 块。与前一次读取的结果不同。

Repeatable Read(RR)可重读

  • 这是 MySQL InnoDB 的默认事务隔离级别
  • 它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行
  • 此级别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行,例如:
A: start transaction
  B: start transaction
A: select * from account // 只有id = 1
  B: insert into account(id, balance) values(2, 0)
  B: commit
A: select * from account // 发现有id = 1 和 id = 2
A: commit
  • 很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于 updatedelete,而幻读的重点在于 insert
  • InnoDB 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题

InnoDB 实现方式:

  • 普通的 select 使用快照读(snapshot read),这是一种不加锁的一致性读。
  • 加锁的 selectupdatedelete 等语句,它们的锁,依赖于它们是否在唯一索引上使用了唯一的查询条件,或者范围查询条件:
    • 在唯一索引上使用唯一的查询条件,会使用记录锁(record lock),而不会封锁记录之间的间隔,即不会使用间隙锁(gap lock)与临键锁(next-key lock)。
    • 范围查询条件,会使用间隙锁与临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录,以及避免不可重复的读。

Serializable 可串行化

  • 这是最高的隔离级别
  • 它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。
  • 在这个级别,可能导致大量的超时现象和锁竞争

InnoDB 实现方式:这种事务的隔离级别下,所有 select 语句都会被隐式的转化为 select ... in share mode.

总结

InnoDB 实现了SQL92标准中的四种隔离级别

  • 读未提交:select 不加锁,可能出现读脏;
  • 读提交(RC):普通 select 快照读,带锁的 select / update / delete 会使用记录锁,可能出现不可重复读;
  • 可重复读(RR):普通 select 快照读,带锁的 select / update / delete 根据查询条件情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;
  • 串行化:select 隐式转化为 select ... in share mode,会被 updatedelete 互斥;
  • InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC

InnoDB,快照读,在RR和RC下有何差异?

参考:InnoDB,快照读,在RR和RC下有何差异?

MySQL 数据库,InnoDB 存储引擎,为了提高并发,使用 MVCC 机制,在并发事务时,通过读取数据行的历史数据版本,不加锁,来提高并发的一种不加锁一致性读(Consistent Nonlocking Read)

  • 事务总能够读取到,自己写入(update / insert / delete)的行记录
  • 在 Read Committed(RC)下,快照读总是能读到最新的行数据快照,当然,必须是已提交事务写入的
  • 在 Repeatable Read(RR)下,假设某个事务首次 read 记录的时间为 T,则未来不会读取到 T 时间之后已提交事务写入的记录,以保证连续相同的 read 读到相同的结果集

例如:数据表中的数据为 {1, 2, 3},现在两个并发事务 A,B 执行的时间序列如下:

A1: start transaction;
         B1: start transaction;
A2: select * from t;
         B2: insert into t values (4, wangwu);
A3: select * from t;
         B3: commit;
A4: select * from t;

在 Read Committed(RC) 模式下:

  • A2 读到的结果集是 {1, 2, 3}
  • A3 读到的结果集也是 {1, 2, 3},因为 B 还没有提交;
  • A4 读到的结果集还是 {1, 2, 3, 4},因为事务 B 已经提交;

在 Repeatable Read(RR) 模式下:

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

推荐阅读更多精彩内容

  • 一、数据库事务隔离级别 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read c...
    atok阅读 1,599评论 2 10
  • 数据库中经常被问到四大特性和隔离级别,一般都是涉及到概念性问题,在此做一些整理总结,方便理解。 1、事务的隔离级别...
    Hughman阅读 1,872评论 0 5
  • 当一个系统访问量上来的时候,不只是数据库性能瓶颈问题了,数据库数据安全也会浮现,这时候合理使用数据库锁机制就显得异...
    初来的雨天阅读 3,549评论 0 22
  • 文/阅先生 尹志平占有了小龙女的初夜,可是金庸笔下的尹志平并不坏,只是令人讨厌。但对很多读者来说,尹志平的令人讨厌...
    岳鲜阅读 7,324评论 2 6
  • 清晨,太阳己暖暖地晒到了床边。因为双休,所以也懒得起床。享受这温暖而休闲的时光也是人生的一大乐趣。 外面偶尔听...
    食之乐阅读 1,074评论 21 23