在上一篇InnoDB可重复读隔离级别是如何实现的文章中,提到了快照读,MySQL通过MVCC中快照读的方式解决不可重复读问题,那么在RR级别下就一定能避免不可重复读吗,我们来一起看下。
快照读:
在RR隔离级别下,同一事务中后边所有这样的读读到的都是第一个这样读的快照,
或是被当前事务刷新过的快照,这样做到了可重复读。
需要注意这个被当前事务刷新过的快照,当事务中发生了当前读
(在默认隔离级别下,普通的select就是快照读,而insert、update、delete、select … lock In share mode、select … for update,特别是写操作,只能是当前读,否则会发生write skew问题。),
事务会刷新readView,也就是快照snapshot,那么可能会看到下面的现象。
1、第一次查询的时候codepoint = 97;
生成快照。
2、修改codepoint = codepoint + 1;
这个时候是当前读,在此基础上修改后刷新snapshot。
3、第二次查询的时候codepoint = 101;
上一步当前读读到的codepoint的值是被其它事务修改后的100。
mysql> SELECT * FROM char_encode WHERE glyph = 'a';
+-------+-----------+
| glyph | codepoint |
+-------+-----------+
| a | 97 |
+-------+-----------+
1 row in set (0.03 sec)
mysql> UPDATE char_encode SET codepoint = codepoint + 1 WHERE glyph = 'a';
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM char_encode WHERE glyph = 'a';
+-------+-----------+
| glyph | codepoint |
+-------+-----------+
| a | 101 |
+-------+-----------+
1 row in set (0.03 sec)
等等,怎么发生了不可重复读,这不违反可重复读隔离级别吗。。。
但是Who cares?毕竟官方都说了:
“This is not a bug but an intended and documented behavior.”
奈何本人没文化,去找百度翻译下:
这不是bug,而是刻意为之。
说明MySQL是允许这样的。
参考文章: