MVCC 写写操作提交时版本对比的问题

2019-11-28 10:27:17 +08:00
 ShutTheFu2kUP

事务 A (版本号为 2 )

1、START TRANSACTION;

2、SELECT * FROM test_mvcc WHERE id = 1;

6、UPDATE test_mvcc SET `value` = 'b' WHERE id = 1;

7、COMMIT;

事务 B (版本号为 3 )

3、START TRANSACTION;

4、UPDATE test_mvcc SET `value` = 'c' WHERE id = 1;

5、COMMIT;

SQL 语句前面的序号为执行顺序,事务 A 开始做了一个快照读。然后事务 B 开启,修改数据并提交,此时数据的版本号应该是 3。这时候事务 A 也修改数据,然后提交的时候发现数据库中数据的版本号比自己的大,所以修改失败回滚操作。

以上是最近通过学习 MVCC 我认为理论上应该出现的情况,然后我自己测试发现事务 A 还是能提交成功,这究竟是什么原因?难道是哪里的理解有偏差吗。(当前数据库隔离级别为 Read Repeatable )

4548 次点击
所在节点    MySQL
12 条回复
sun1991
2019-11-28 10:43:48 +08:00
因为事务 B 已经 commit 了呀, 你试试去掉 5, 看看执行是不是卡在那里了. 如果你期望事物 A 报错回滚, 那么需要更高一级的隔离级别.
zhenhuaYang
2019-11-28 10:44:45 +08:00
首先是 repeatable read 不是 read repeatable

事务 A 为什么不能提交成功? mvcc 多版本并发控制和 next-key locks 间隙锁搭配实现了事务的可重复读而已,只不过是让 mysql 可以重复读取数据而已,为什么不能提交成功呢?

你说的事务 B 提交数据后,事务 A 发现此时的数据库提交版本要高于自己,就不会提交成功会回滚,你说的是乐观锁吗?

乐观锁是提交版本大于当前数据库提交版本才会去更新数据。
ShutTheFu2kUP
2019-11-28 10:59:02 +08:00
@zhenhuaYang 首先感谢大佬指正。其次,按照你的意思就是 MVCC 中并没有实现这种乐观锁的机制是吗?因为最近学 MVCC 相关知识,国内博客资料和 MySQL 官方文档在这块上都描述的模糊不清,一人一种说法,搞得我学的真的是一头雾水。
zhenhuaYang
2019-11-28 11:03:07 +08:00
@ShutTheFu2kUP 你可以看看这篇文章,或许看完你就恍然大悟了。https://tech.meituan.com/2014/08/20/innodb-lock.html
ShutTheFu2kUP
2019-11-28 11:03:55 +08:00
@zhenhuaYang 好的,谢谢
newtype0092
2019-11-28 11:11:30 +08:00
事务是没有版本号的吧,事务 A 和事务 B 里这条数据的版本号都是 v2,B 提交后数据版本变为'c'(v3),但在 A 中,只要不修改,重复读取数据,看到的还是'b'(v2),这就是“可重复读”的意思吧。
banks0913
2019-11-28 12:12:25 +08:00
因为 UPDATE 操作属于当前读,即基于最新数据去进行更新,不像 SELECT 操作是基于 mvcc 读当前事务版本的数据快照。
peyppicp
2019-11-28 13:05:46 +08:00
1 楼+7 楼组合起来就是正解了。
0NF09LJPS51k57uH
2019-11-28 20:33:27 +08:00
@zhenhuaYang 今天看了一下午你发的这篇文章,我还是不能认同你的回复,按照我的理解,A 事务先发起,B 事务后发起,A 事务先 select 以后,会给对应的 rows 以及区间加上行锁以及 gap 锁,这种情况下,B 事务的 update 应该是无法执行的。我看文中对 Next-Key 锁介绍的部分是这么说的。还是我的理解有误?请指教!
0NF09LJPS51k57uH
2019-11-28 20:38:32 +08:00
重新尝试着理解了一下,是不是事务 A 的 select 获取的只是 s 锁,事务 B 的 update 获取的是 x 锁,事务 B 在 commit 以后释放了 x 锁,所以事务 A 可以 update ?我来调换一下 5 和 6 的步骤验证下看看
@zhenhuaYang
0NF09LJPS51k57uH
2019-11-28 21:01:24 +08:00
再次挖掘了一下,理解到:事务 A 第 2 步,是快照读,不会加锁,事务 B 第 4 步是当前读,会加 X 锁,紧接着的第 5 步释放了 X 锁。
zhenhuaYang
2019-11-29 09:34:23 +08:00
@phantomzz 嗯嗯,对,没错。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/623861

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX