mysql 可重复读 悲观锁,mysql可重复读和幻读,gap锁

标签:

一直以来,对MySQL的幻读和gap锁不是很清楚,特此研究一下:

mysql的默认事务级别是:可重复读

其中可重复读是通过mvcc来实现的又叫快照读,在事务中的读操作通过对当前的数据库中记录一个版本,以后的读操作只会读取记录的版本,因此相当于对数据库的数据建立了一个快照数据,因此叫做快照读,其不用对数据库中的数据进行加锁又叫做乐观锁。

同时RR事务级别的mysql通当前读和gap锁来解决幻读,其本质是通过对数据库周边记录进行加悲观锁(读锁(共享锁)和互斥锁(写锁))【gap锁】来解决幻读。

1.什么是幻读问题

RR事务隔离级别号称可以解决幻读的问题(通过当前读加锁来实现)

第一步建表并插入5条记录:

3fd97a78b341ce142a46a669a16c0755.png

接下来我们看下大部分mysql所说的幻读现象:

事务1(开启事务查询发现没有记录6准备插入):

e28990b20e804f074da28d845e165ee9.png

事务2(开启事务,发现没有记录6插入,并提交事务):

c5291f137b6611616de177e2fa5c387f.png

事务1:查询发现没有记录6,现在开始进行插入6:

81fb671c5e81a17b097b37c05d5b817a.png

没有的记录我要插入却告诉已经存在,这就是通常说的幻读。

2.gap锁(当前读)解决幻读问题

mysql说对数据加锁不管共享锁还是互斥锁就能解决幻读的问题

开启一个事务1(加上共享锁解决幻读的情况):

开启事务2(查询发现没有记录8,准备插入)

可以发现事务2被阻塞,不准插入,除非事务1提交。因此在事务1中插入记录8是能够成功的。

事务1插入记录8,最后可以查询出自己插入的数据,但是更新一条不存在的数据是不会查询出来的,最后提交事务:

事务2阻塞的操作会爆重复异常:

因此对一个事务加上悲观锁(共享锁或者互斥锁)是能够保证幻读不会出现的,并且谁先加锁,谁就能够保证check and insert是成功的。如果你需要每个事务的check and insert都能成功,那么你不要加共享锁,直接加互斥锁。那么事务会直接阻塞在加锁阶段,就不会出现check and insert 失败的情况。

事务1加上互斥锁

事务2也想加互斥锁,BOOM你只能失败:

3.RR没有解决的幻读

场景:我们知道grap锁能够将右边的记录进行加锁,因此我要统计表记录的数量,我只需要对最大记录加锁就行了

事务1:对最大记录互斥加锁,准备计算表中记录数量。发现数量为8,并且不存在3和4的记录。

事务2:插入缺失记录3和4成功,但是插入id为100的记录被锁住,OK事务2可以提交了。

事务1:在事务1在事务2插入数据后进行查询总量,发现数量还是6,OK很完美

事务1:接下来我发现事务1中没有3和4这条记录,我进行一次无用的更新会发生什么?

OK,最终问题终于出现了,为什么我更新两条不存在的记录,我能够更新成功,并且我再次统计的时候,数量添加了两条?并且我重新读取,发现结果不一样了,不是说可以重复读吗?加锁可以解决幻读吗?

PS:如果一个事务里面插入或者删除会改变记录的数据,这个是合理的不是幻读。更新应该只会修改数据记录,这个也是合理,同样不是幻读,都是可重复读的。但是更新出现新的记录就是一种异常的情况。

author:王子瑞

标签:

来源: https://blog.csdn.net/Aliloke/article/details/85130200

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值