登录
首页 >  数据库 >  MySQL

事务进阶--快照读与当前读

来源:SegmentFault

时间:2023-01-20 07:56:29 319浏览 收藏

本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《事务进阶--快照读与当前读》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~

快照读

比如我们新建一个表,然后新建两行数据,现在表的内容是这样的

image.png

我们新建一个事务,称为Query1。

begin;
    select * from test1;  ## 第一次查询
    select * from test1;  ## 第二次查询
commit;

然后执行第一次查询的语句,查询内容跟表内容一样,正常。

image.png

然后我们新建一个事务,执行update操作,我们称为Query2

begin;
update test1 set `name` = 'yunzhi' where id = 1;
select * from test1;
commit;

执行他Query2,此时查询结果为

image.png

然后再执行Query1的第二次查询
image.png

我们发现Query1的查询和Query2的查询的结果是不同的。

这就涉及到mysql的多版本并发控制技术, 简称MVCC(Multi-Version Concurrency Control)。
基于上边的例子,我们可以理解为当开启一个事务的时候,会对事务设置一个版本号,且版本号逐个递增,同时对每行数据进行新增,更新,删除也会同步更新版本号同当前事务版本号。当在事务内进行查询操作的时候,
默认执行快照读操作,快照读只能查询到小于等于当前版本的数据。
让我们复盘一下刚才的操作。
我们认为新增数据时version = 1;所以每行数据版本号为1。
我们在新建Query1事务的时候,version = 2;

begin; ## version = 2;
    select * from test1;  ## 第一次查询
    select * from test1;  ## 第二次查询
commit;

image.png

我们再新建Query2事务的时候,version = 3;

begin;  ## version = 3;
update test1 set `name` = 'yunzhi' where id = 1;
select * from test1;
commit;

image.png

再执行Query1的第二次查询时,

image.png

因为Query1的对应版本号为2,无法查到对应版本号为3的'yunzhi'数据。

快照读解决了不可重复读问题。不可重复读,即前后多次读取,数据内容不一致

当前读

对于会对数据修改的操作(update、insert、delete)都会执行当前读。假设要update一个记录,另一个事务已经delete这条数据并且commit了,这样就会产生冲突,所以update的时候肯定要知道最新的信息。
在执行修改数据的时候,首先会执行当前读,然后把返回的数据加锁,之后执行修改数据。加锁是防止别的事务在这个时候对这条记录做什么,默认加的是排他锁,也就是你读都不可以,这样就可以保证数据不会出错了。
想要手动执行当前读需要在后缀加

for update
,如

select * from test1 for update;

如果一个事务执行当前读操作且不提交,另一个事务是无法执行当前读操作的。这也说明了当前读加了锁。

总结

mysql查询操作默认执行快照读操作,修改数据会执行当前读操作。

以上就是《事务进阶--快照读与当前读》的详细内容,更多关于mysql的资料请关注golang学习网公众号!

声明:本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>
评论列表