前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >InnoDB的RR级别解决幻读问题 - X锁 Next-Key Lock

InnoDB的RR级别解决幻读问题 - X锁 Next-Key Lock

原创
作者头像
莫闲得慌
修改2022-07-08 17:19:37
1.4K0
修改2022-07-08 17:19:37
举报
文章被收录于专栏:芒格芒格

幻读 : 针对update和delete操作里面的where条件查找满足条件的记录,InnoDB引擎会返回的所有满足条件的数据。

实际场景

  • select返回了2条数据,update却成功处理了3条。
  • insert某条不在的数据时忽然报错说唯一索引冲突。(查询不到,插入失败)

【幻读】则关注: 行数量是否发生变化。【不可重复读】关注: 行内容是否发生变化。

能解决幻读问题的有两种:

  1. Serializable隔离级别。
  2. RR隔离级别下对“当前读”操作加临键锁Next-Key Lock

一个事务能读到的数据视图有 : a) MVCC快照读: 初始看到的是该事务第一次查询获取到的已提交数据的快照版本。如果没有发生“当前读”,一直都如此。 b) 事务“当前读” :被其他事务更新且提交后的数据。(事务自己更新未提交的也能看到)

【插入、更新、删除】操作到的数据为当前的最新值版本,称为当前读

直接在另外事务执行commit | rollback 后再次查询也可以读到最新版数据。 加锁是实现在索引上的,如果没有索引则会全表加锁,不同场景下的锁是不一样的。


准备操作:

set session transaction isolation level REPEATABLE READ; -- 设置RR级别 select @@tx_isolation; SET AUTOCOMMIT= 0; -- 设置手动处理事务 show session variables like 'autocommit'; start TRANSACTION

通过2个事务的交替执行进行验证。

1、A、B 事务初始查询看到的数据视图

A、B 事务初始查询:select * from test;
A、B 事务初始查询:select * from test;

2、B事务更新数据但未提交时:

A看到的还是事务开始时初始查询的数据视图;===> 这个是肯定的,除非隔离级别是 "读未提交"

B能看到更新后的视图,虽然此时未提交。

3、B事务提交时:

A依然是事务开始时初始查询的数据视图,B看到的是自己修改后的数据视图; 若此时有新的事务C来查看则能看到commited的数据。 ====> RR: 快照读,解决不可重复读问题; RC: 每次读最新事务提交的结果。

B事务更新提交后是看到自己更新的数据:update test set token = "ffff";
B事务更新提交后是看到自己更新的数据:update test set token = "ffff";

4、此时A事务指定相同字段过滤更新:

A: update test set token = "mmmmm" where token = 'lllll';
A: update test set token = "mmmmm" where token = 'lllll';

结果: 更新0条 。 ===> 虽然A事务select时看到的是初始视图,是有符合该过滤条件的,但在最新的commited数据集里都不符合条件,所以无法更新成功

important! : 此时A事务直接执行commit ,会看到最新commited后的数据!


5、此时A事务进行全量更新但未提交:

A:update test set token = "mmmmm";
A:update test set token = "mmmmm";

结果: 能更新这2条记录。===> 事务能看到自己更新后的视图,即使未提交。

6、此时B事务接着插入一条新的数据,id值比现有的都要大。

B:insert into test value(9,9,'9');
B:insert into test value(9,9,'9');

结果: 因为A事务还没有commit, 会造成锁等待阻塞。 ===> "当前读"进行了加锁操作。 (按当前测试的sql来说,因为没有使用到索引,此时加的是全表行锁和含上下界的Gap锁)


7、A事务进行commit操作:

结果:新的C事务(RR + autoCommit)数据真实视图已经更改。

A事务进行commit操作后
A事务进行commit操作后

但B事务查看到的是:自己事务中提交更新后的视图。

B事务查看
B事务查看

8、B事务新增加一条数据,并提交

结果:

C事务(RR+ autoCommit)真实视图已经更改 , B事务看到也是如此

B: insert into test value(9,9,'9'); commit;
B: insert into test value(9,9,'9'); commit;

A事务看到没有变化,没有新加的这个“9”。

A事务看到并没新增加的"9"
A事务看到并没新增加的"9"

9、A事务进行全局更新提交update test set token = "ccccccccccc"; commit; (是否有过滤条件不影响最终结论,只影响加锁的类型)

(需要注意的是: 这里仅单独执行commit也能达到效果,不提交也是看不到多的那条数据的)

此时A事务再来select下:

A提交更新后select看到的数据视图
A提交更新后select看到的数据视图

结果: 多了一条数据值!也能正确commit。 这样就说明解决了幻读问题


插入一个已经存在的主键时,insert时先加的是共享读锁S锁来判定唯一约束 。

主键2已经存在,所以insert时先加的是共享读锁来判定唯一约束
主键2已经存在,所以insert时先加的是共享读锁来判定唯一约束

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档