mysql原理(十) 当前读与快照读
2021-08-19 本文已影响0人
我犟不过你
首先我们做一个模拟,执行以下的sql,其中有如下图数据:
image.png时间 | 会话1 | 会话2 | 会话3 |
---|---|---|---|
1 | begin; select * from t_student where id = 2 |
||
2 | update t_student set age = age + 1 where id =2;; | ||
3 | begin; update t_student set age = age + 1 where id =2;; |
||
4 | select * from t_student where id =2; COMMIT |
||
5 | select * from t_student where id = 2; | ||
6 | COMMIT; select * from t_student where id = 2; |
我把执行结果按照表格如下展示:
时间 | 会话1 | 会话2 | 会话3 |
---|---|---|---|
1 | 15 | ||
2 | |||
3 | |||
4 | 17 | ||
5 | 15 | ||
6 | 17 |
分析:
在会话1当中,只有当会话1的事务提交后,才能查到最终会话2更改的数据。
在会话2当中,开启事务后更新数据,之后查询发现数据变成了17。
针对上面的现象我们进行个原理分析:
实际上产生上述显现是因为InnoDB采用的MVCC(多版本并发控制),其中针对每条数据会有它自己的事务id,以及一个最大事务id。针对事务中数据每次修改,会产生不同的版本。
1)假设开始id = 2的数据,其事务txid = 1000;
2)当会话1开始,此时txid变成了1001,而会话2开启,txid又变成了1002,同理会话3会变成1003,此时都生成了不同版本的快照。
3)会话1在事务当中去读取时候,采用了快照读的方式,即拿到一个1001的事务id,此时只会读取小于等于自己版本的数据,所以在事务中最终只能拿到值为17的数据。
4)会话2在更新数据的时候,采用的当前读的方式,即对数据增加X锁,获取最新的事务id,读取最新的版本数据。所以在更新之前,就读取到了age的年龄是16,之后在进行+1,得到17.
总结一下:
快照读解决了幻读的问题,即多次读取数据不一致的问题。
update、insert、delete都会执行当前读,防止并发更新数据导致数据错误,此过程或添加X锁。