mysql mvcc 机制控制幻读问题

2018-10-24 10:14:34 +08:00
 cc959798

比如说 事务 A select * from tb1

里面有三条数据

然后开启一个事务 B

select * from tb1 里面也是三条

然后事务 A 插入一条并提交

事务 B 里面看到的还是三条

但是根据 mysql 版本控制,每行记录都有一个时间戳是事务的 id,新的事务 id 比老的事务 id 要大,事务 select 找到的行是创建时间比当前事务 id 要小的或者等于的行,但是上面的例子是事务 B 的 id 肯定比事务 A 要大,但是提交了依然看不到这是为什么?

3602 次点击
所在节点    MySQL
14 条回复
kuko126
2018-10-24 12:01:22 +08:00
看你事务隔离级别,RR 下 B 看不到 A 的插入是正常的
lsongiu
2018-10-24 13:29:51 +08:00
mysql 默认隔离级别是可重复读,这不就是可重复读吗
cc959798
2018-10-24 13:49:46 +08:00
@kuko126 肯定是默认的
cc959798
2018-10-24 13:51:10 +08:00
@lsongiu 问题是按照网上的原理说明,后开启的事务是可以查到自己开启后提交到事务的新插入的或者说变更的
kuko126
2018-10-24 13:59:07 +08:00
@cc959798 mysql 的 RR 是解决了幻读问题的 所以看不到
lsongiu
2018-10-24 14:15:31 +08:00
@cc959798 那得等 A 事务提交之后才能查出来
Codingless
2018-10-24 14:17:45 +08:00
可见性的判断不是通过比较行记录事务 ID 和当前事务 ID 的实现的,是通过比较行记录对应 MVCC 版本链上某个节点的事务 ID 和当前查询对应的 ReadView 中若干个值(具体的比较规则代码里很清楚)实现的,具体可以了解一下 MVCC 和 ReadView 实现相关的内容。
zjsxwc
2018-10-24 14:33:07 +08:00
正常,Mysql 默认事务隔离级别 Repeatable Read 是会幻读的,想要不幻读需要开 Serializable 级别隔离
cc959798
2018-10-24 14:52:08 +08:00
@lsongiu 事实是事务 A 提交了也查不出来,这个也是满足可重复读的特性
lsongiu
2018-10-24 15:00:47 +08:00
A ->开始 -> 修改 -> 提交
b ->开始 ->第一次查询 ->第二次查询 。这时候查出出来的都是修改过的

A ->开始 -> 修改 -> 提交
b ->开始 ->第一次查询 ->第二次查询 。这时候查出出来的都是修改前的
lsongiu
2018-10-24 15:01:11 +08:00
。。。这万一还自动去空格啊。。白写了
NNS71L068O2v70DB
2018-10-24 15:01:49 +08:00
我的理解,判断的不是事务 ID,而是系统版本号。每个行都有一个字段存系统版本号,版本号可能是时间戳,所以 a insert 操作的话,修改行版本号(时间戳)> b 的事务 id,所以对 b 不可见
cc959798
2018-10-25 10:26:24 +08:00
@jojojo 但是怎么解释老的事务比如 A 能看到这个新的修改,A 的 id 是小于新产生的版本号的,感觉网上讲的都不清不楚,而且大部分都是复制粘贴
cc959798
2018-10-25 10:28:58 +08:00
@lsongiu 对白写都是一样的。现在可以知道的是默认隔离级别下,两个事务开启,无论谁先谁后,只要新的事务再老的 commit 之前开启的话,两个事务里面无论怎么改,select 都是自己看到的,除非是加锁,就是直接读而不是快照读,关键不知道他是怎么实现的

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

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

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

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

© 2021 V2EX