mysql可重复读概念_Mysql可重复读原理

概念

可重复读的实现

Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(读已经提交的,其实是读早于本事务开始且已经提交的),但是不能看到其他事务对已有记录的更新(即晚于本事务开始的),并且,该事务不要求与其他事务是“可串行化”的。

这句话的核心,是“但是不能看到其他事务对已有记录的更新”,那么RR隔离级别是怎么保证这一点的呢?

实现原理

使用MVCC(多版本并发控制)。InnoDB为每行记录添加了一个版本号(系统版本号),每当修改数据时,版本号加一。

在读取事务开始时,系统会给事务一个当前版本号,事务会读取版本号<=当前版本号的数据,这时就算另一个事务插入一个数据,并立马提交,新插入这条数据的版本号会比读取事务的版本号高,因此读取事务读的数据还是不会变。

注意点

但是,当前事务想再写这行数据的话,还是以数据库提交的数据为准。并且会加行锁,其他的事务要再来修改的话,就得等到当前事务结束。

举例:

我们先看看现象,再分析原理。我的mysql版本是5.5。

下面是一张表,只有一条数据,并且我开启了事物

7039cecac4eec3956338a72b611cb6d1.png

此时,另一个事物将record加1,因此我在开启一个命令行客户端,执行下面的命令:

734afa05b1a89b697eaaf1a3525f1f27.png

成功加1之后,实际上,数据库中record肯定是2。

然后回到之前的客户端,再查一次:

dea980243b15ecb43d7b7456353290fe.png

没毛病,record还是1,果然是可重复读。有些人以为mysql的可重复读是通过行锁实现的,

从上面可以知道,肯定不是,如果是的话,第一次select * from test的时候,id=1的记录就会加行锁,我都加行锁了,我还没提交,另外的事物是怎么update成功的。

结论就是mysql使用的MVCC(多版本并发控制),MVCC详解可以看:https://blog.csdn.net/whoamiyang/article/details/51901888

我们继续,我之前的第一个事物还没提交,不过提交之前,我也想加1;

953e7ed6f61692dba673b98d75a9f3b5.png

加完之后我再查一下,额,record是3,好像很奇怪,但也不奇怪。

其实,update test set record=record+1 where id=1;这条语句中,在加1之前,他知道自己等于2,然后2+1=3。

也就是说,update时读取数据是最新版本的数据,而select是到当前事物版本为止的数据。当更新成功之后,当前版本即为最新版本,再次select,读取的是最新的数据。

在这里讨论下乐观锁的必要性。下面是乐观锁的实现,实现乐观锁,我们一般会这么做

update test set record=record+1 where id=1 and record=1;

如果不用乐观锁,你用select读取到的值其实根本不准确。除非你开启悲观锁,像下面这样:

select * from test where id=1 for update;

这样可以读取到最新的内容,同时在你当前的事物提交之前,其他事物的update此条记录将会锁等待。

故事到此,还没有结束,此时我们开启事物三,也做加1操作看会发生什么。

f26e9a7a7adfa6e61a208e2018234c4c.png

结果是,锁等待超时,也就是说(事物一)在更新完后,会加行锁,这个应该比较好理解。事物中,刚开始查询的时候是不会加行锁的,但是当有更新操作之后,会加行锁,直到事物提交。

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值