MySQL到底在RR层面解决幻读了吗?

Y说

hi,好久不见。

最近工作上有一些变动,文章很少更新。不过平时还是有收集一些文章idea,后面有空会慢慢写~

这篇文章是因为之前写了一篇关于InnoDB锁的文章,在个人网站上有读者留言问“间隙锁一定程度上解决了幻读问题,为什么不是完全解决了呢”,所以重新把MySQL中关于幻读的问题梳理了一遍。

文章写完后,发现自己也有新的收获,又了解了一些奇怪的知识点,哈哈。

隔离级别与幻读

数据库的事务有四种隔离级别,这四种隔离级别分别应用在不同的场景,隔离级别越低,并发性越高,但数据一致性就越差。四种隔离级别存在的问题如下表:

隔离级别 脏读 不可重复读 幻读
Read uncommitted
Read Committed
Repeatable Reads
Serializable

MySQL InnoDB默认的隔离级别是Repeatable Reads(RR),但它通过MVCC+间隙锁解决了绝大部分幻读(后面会解释为什么是绝大部分而不是全部)的问题。

什么是幻读

简单来说,一个事务同样的查询条件,两次查询到的数据行数不一样,它就产生了幻读。

举例来说,对于下面的数据:

id c d
5 5 5
10 10 10
15 15 15

事务A第一次查询sql:

SELECT * FROM demo WHERE id < 10;

这个时候只能查出 id = 5 的数据。

而这个时候如果事务B插入了一条id = 6的数据:

INSERT INTO demo VALUES (7, 7, 7);

然后A进行第二次查询,用同样的sql,如果查到了两条数据:id = 5 和 id = 7,那就是出现了幻读。对于事务A来说,就像幻觉一样,同样的查询条件,查出来的数据多了一行。

这个在业务场景中也很常见:先查询名为“编了个程”的公众号,发现不存在,于是我准备创建的时候,却发现已经被其它事务创建了,于是唯一索引提示我创建失败,改名称已存在。那我这个事务岂不是出现幻觉了?明明刚刚查过不存在的呀~

快照读和当前读

快照读

在MySQL中,查询语句分为两种,一种是简单的select操作,属于快照读,不加锁。它读的是记录的快照版本(这个版本跟MVCC有关,后面再细聊)。

select * from table where ?;

当前读

另一种是要加锁的特殊的读操作,它读的是记录的最新版本。

-- 共享读锁
select * from table where ? lock in share mode;
-- 共享写锁
select * from table where ? for update;

-- 增删改也属于当前读,因为要先看这条记录在不在
insert into table values (…);
update table set ? where ?;
delete from table where ?;

快照读下的幻读

InnoDB是通过MVCC来解决当前读下的幻读问题的。每个事务会有一个递增的事务ID,每行记录都有两个隐藏字段:创建版本和删除版本。在进行操作时,遵循以下规则:

INSERT

保存当前事务id作为行版本号

DELETE

保存当前的事务id到这行数据的“删除版本”。

UPDATE

插入一行新记录,保存当前事务id作为行版本号,同时保存当前事务id到原来的行的“删除版本”。

SELECT

  • 只读取版本小于等于当前事务id的行。这样可以保证事务读取都的行,要么之前就存在,要么是这个事务本身自己插入或者修改的。
  • 只读取“删除版本”为空或者小于等于当前事务id的行。这样可以确保事务读取到的行,在事务之前没有被删除。

当前读下的幻读

当前读下的幻读是通过间隙锁(gap_lock)来实现的。在事务A查询的时候,会锁住一个间隙,其它事务往这个间隙插入、删除等操作都是会被锁阻塞的。

关于间隙锁是如何工作的,可以参考我之前写的这篇文章:《InnoDB的行锁,原来为你做了这么多!》,简单来说,间隙锁和插入意向锁互斥,彻底解决了当前读下的幻读问题。

快照读没有完全解决幻读?

是的,MySQL没有完全解决快照读下的幻读问题。

可以做这个实验:

  1. 当前DB已有id 5, 10, 15三条数据。

  2. 事务A查询id < 10的数据,可以查出一行记录id = 5

  3. 事务B插入id = 6的数据

  4. 事务A再查询id < 10的数据,可以查出一行记录id = 5,查不出id = 6的数据(读场景,解决了幻读)

  5. 事务A可以更新/删除id = 6的数据,不能插入id = 6的数据(写场景,幻读不彻底)

这个很好理解,MySQL虽然通过MVCC的版本号来解决了读场景下的幻读,但对于上面第5步那种写场景的情况,其实是无能为力的,因为MVCC毕竟是无锁实现。

所以如果后续要对数据进行写操作,还是通过for update语句上锁比较稳妥,不然就可能会出现上面第5步那样的问题。

求个支持

我是Yasin,一个坚持技术原创的博主,我的微信公众号是:编了个程

都看到这儿了,如果觉得我的文章写得还行,不妨支持一下。

文章会首发到公众号,阅读体验最佳,欢迎大家关注。

你的每一个转发、关注、点赞、评论都是对我最大的支持!

还有学习资源、和一线互联网公司内推哦

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

推荐阅读更多精彩内容