数据库隔离级别的理解

文章初衷

最开始听到隔离级别这个词是在大学上数据库课的时候老师讲到,当时听得一头雾水最终也没理解到,就不了了之了。到毕业开始找工作,每次面试前的知识点整理,总能看到隔离级别这个词,但是每次都停留在背书式的记住。一直对隔离级别这个词感觉很陌生甚至有点抗拒。最近公司在做技术分享,我想分享一下MVCC的理解,在查资料的过程中发现MVCC 跟 隔离级别、undo log等知识点关联还是很密切的,所以也顺便系统的去学习一下隔离级别。

开始正题

我对隔离级别的理解:事务之间互相影响的程度。比如在A事务中需要查询和修改用户余额字段,现在进来了一个B事务也改动了用户余额的字段,隔离级别就规定B事务的改动对A事务的影响程度。

不同的隔离级别导致 A、B两个事务之间的操作有不同的影响。

隔离级别可以理解为处理多事务并发操作数据时的不同策略。下面先列出多事务并发操作可能引起的问题。

ANSI/ISO SQL 定义了 4 种标准隔离级别。
下面根据隔离程度从低到高分别说明。

读未提交(Read uncommitted)

这个隔离级别规定:在查询数据时能读取到未提交事务中修改了的数据结果。

字面上理解起来可能比较难,我们直接来看例子:

时间点 事务A 事务B
T1 开启事务
T2 开启事务
T3 查询余额,结果是100
T4 修改余额为150
T5 查询余额,结果是150
T6 提交事务
T7 提交事务

上面例子可以看到,事务B在修改了余额后,事务A能马上查询到修改后的结果。这就是 读未提交 的效果,结合上面这个例子去理解的话,读未提交就是:事务A能 事务B 未提交 的数据。

这个隔离级别会产生一个问题。假如事务B最终没有提交事务,而是回滚了。可以看一下下面这个例子:

时间点 事务A 事务B
T1 开启事务
T2 开启事务
T3 查询余额,结果是100
T4 修改余额为150
T5 查询余额,结果是150
T6 事务回滚
T7 查询余额,结果是100
T8 提交事务

由于事务B最终回滚了,事务A在 时间点T4 拿到的余额150是一个脏数据,我们称这个问题为:脏读

总结来说,在读未提交隔离级别下,数据的改动能实时的被查询出来,这带来的问题是会出现 脏读。

读已提交(Read commited)

理解了上面的读未提交,再来看读已提交的话应该就比较好理解了。

读已提交隔离级别规定:只有在事务提交后,事务中修改了的数据才能被其他事务查询到。

我们还是来看一下例子:

时间点 事务A 事务B
T1 开启事务
T2 开启事务
T3 查询余额,结果是100
T4 修改余额为150
T5 查询余额,结果是100
T6 提交事务
T7 查询余额,结果是150
T8 提交事务

根据上面这个例子可以看到,事务B 在 时间点T4 修改了余额但未提交事务,事务A 在 T5 查询余额时,是查不到事务B修改过的余额。在事务B 提交事务后,事务A再去查询余额,就能拿到事务B 修改后的余额。

结合这个例子去理解的话,读已提交就是:事务A能 事务B 已提交 的数据。

这个隔离级别不会出现脏读,但会有另外的问题。可以看回上面的例子,事务A 对余额做了多次查询,却得到了不同的结果,在我们实现部分业务逻辑时这可能是一个不正常的现象。因为重复读同一条数据会得到不同的结果,所以我们称这个问题为:不可重复读

总结来说,在读已提交隔离级别下,数据的改动在事务提交后能实时的被查询出来,这带来的问题是会出现 不可重复读。

可重复读(Repeatable read)

这个隔离级别名称我认为是比较抽象的。由于这个隔离级别解决了 读已提交 产生的不可重复读问题,所以这个隔离级别就叫 可重复读。

可重复读隔离级别规定:事务只能查询到事务开始之前已提交的数据。

我们还是通过具体例子来说明:

时间点 事务A 事务B 事务C
T1 开启事务
T2 开启事务
T3 查询余额,结果是100
T4 修改余额为150
T5 查询余额,结果是100
T6 提交事务
T7 查询余额,结果是100
T8 开始事务
T9 查询余额,结果是150
T10 提交事务
T11 提交事务

事务B 在事务A 开始之后才开始,所以事务B的更新操作不会影响到事务A 的查询,即使事务B提交了,事务A还是拿到余额100的结果。事务C 在事务B 提交之后才开始,所以事务C 能查到事务B 修改后的结果。

可以看到事务A每次查询都能得到同样的结果,这解决了 读已提交 的不可重复读问题。

但这个隔离级别还是存在另外一个问题:幻读。我认为 幻读 这个问题是最难理解的,我们先来看一下例子:

假设我们现在表中有两条数据:

id account balance
1 张三 1000
2 李四 2000

然后我们进行以下操作

时间点 事务A 事务B
T1 开启事务
T2 开启事务
T3 新增一个王五的账号,余额3000
T4 提交事务
T5 查询列表,返回 张三、李四 两条数据
T6 更新王五的余额
T7 查询列表,返回 张三、李四、王五 三条数据
T8 提交事务

上面例子时间点 T5,T6,T7 看上去很诡异,但是实际操作的确也是得到这样的结果。我是这样理解的:

  1. 事务A 在 T5 查询不到王五的数据,那是因为事务B在事务A之后开始,这里满足 可重复读 隔离级别的规则。
  2. T6 能更新王五这条数据应该是最让人迷惑的。但其实我们细想一下,这里是事务A 的更新操作,而我们之前谈到的隔离级别都是讲的select操作。在这里事务A 通过select语句的确是查询不到事务A 的数据,但是update 操作根据where其实是能找到这一条数据的。可以理解为,select的查询与update中where查询是不一样逻辑。
  3. T7 这时候能查到王五这一条数据,是因为T6 对王五做了更新操作,导致王五这条数据存在一个事务A操作过的版本。可重复读隔离级别下,是允许查询到当前事务中修改过的数据,所以事务A 这里查得到王五这条数据也是符合可重复读隔离级别的。

上面这个例子,一开始我们查询列表只有2条数据,后来又查到3条数据,这就是我们上面提到的 幻读

幻读 与 不可重复读 有那么一点相像,两者都是在用相同条件多次查询时得到不同的结果。我的理解是,不可重复读更侧重于数据内容的变更,而幻读侧重于由于事务内的一些操作导致本来查询不到的数据变成对当前事务可见。

串行化(Serializable)

这是最严谨的隔离级别,为了不因为多事务并行执行导致数据的不一致,直接规定事务串行去执行。就是上一个事务未结束,下一个事务不会开始。串行化比较好理解,就不做举例了。

前面提到的3种问题(脏读、不可重复度、幻读)在串行化隔离级别下,都不会发生,所以说这个是最严谨的隔离级别。


隔离级别越高,需要消耗的性能越多。

MySQL InnoDB引擎默认使用 可重复读 隔离级别

这里额外说一点,读已提交、可重复读 这两个隔离级别的数据其实是比较特别的。我们再拿可重复读中的例子来看一下:

时间点 事务A 事务B 事务C
T1 开启事务
T2 开启事务
T3 查询余额,结果是100
T4 修改余额为150
T5 查询余额,结果是100
T6 提交事务
T7 查询余额,结果是100
T8 开始事务
T9 查询余额,结果是150
T10 提交事务
T11 提交事务

这个例子中,事务A查到的余额一直是100,而事务B在修改余额后,事务B查询余额结果会是150。不知道大家在这里会不会产生疑问,同一个账户的余额,事务A查的到是100,事务B查到的是150,那数据库中这个账户的余额字段存的究竟是存的100还是150?还是100和150余额同时存在于数据库?这其实是一个叫做 多版本并发控制 的知识点,又称作 MVCC(Multi-Version Concurrency Control)。上面例子中,余额为100和150 的数据是同时存在的,这就是多版本的意思。具体的 MVCC介绍留到下一篇文章再说了。

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

推荐阅读更多精彩内容