前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL中RR隔离级别转换成RC隔离级别案例

MySQL中RR隔离级别转换成RC隔离级别案例

作者头像
星哥玩云
发布2022-08-16 14:43:39
1.3K0
发布2022-08-16 14:43:39
举报
文章被收录于专栏:开源部署

先了解RR(REPEATABLE-READ)和RC(READ-COMMITTED)的区别。

RR隔离级别增加了间隙锁,避免了幻读,并且阻止了不可重复读,让同一个事务里面的查询和修改都是一致的。MySQL默认的隔离级别就是RR。

虽然说RC隔离级别在同一个事务内会存在查询出不同数据的现象,但是这些数据都必然是提交过的,是真实存进硬盘的数据。所以也不用过分担忧,而且RC隔离级别反而降低了锁粒度,也不是毫无用处。Oracle和sql server默认的隔离级别类似RC。

所以说也不是说RC就绝对不好,要看场景来选择,而这里只是简介,不打算深入。

操作流程说明:因系统高并发下,存在多个会话可能同时更新同一条记录的问题,但是值是一样的。问题就在于事务里面存在RR隔离级别转换成RC的问题,造成数据返回不正确,导致代码返回错误,但是数据是准确的。

正常的RR事务

先看当前环境信息:

#当前的mysql版本 mysql> select @@version; +------------+ | @@version  | +------------+ | 5.6.39-log | +------------+ 1 row in set (0.00 sec) #当前的隔离级别 mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation  | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) #当前的binlog格式 mysql> show variables like 'binlog_format'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | MIXED | +---------------+-------+ 1 row in set (0.00 sec)

先看一个正常的事务:

#开启事务 mysql> begin; Query OK, 0 rows affected (0.00 sec)

#开启事务 mysql> begin; Query OK, 0 rows affected (0.00 sec)

#当前记录是一致的 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost |+--------------+|        2000 |+--------------+1 row in set (0.02 sec)

#当前记录是一致的 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost |+--------------+|        2000 |+--------------+1 row in set (0.02 sec)

#这边先更新一条记录 mysql> update m_order_sub set express_cost = 3000 where order_sub_no = 'O152022324482662671828'; Query OK, 1 row affected (0.01 sec)Rows matched: 1  Changed: 1  Warnings: 0

#这边后更新一条记录,但是另一边并没有commit,所以这边处于等待释放锁 update m_order_sub set express_cost = 3000 where order_sub_no = 'O152022324482662671828';

#这边再查询一次,记录成功修改 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost |+--------------+|        3000 |+--------------+1 row in set (0.00 sec)

#提交事务 mysql> commit; Query OK, 0 rows affected (0.01 sec)

#然后锁释放后这边的更新也执行完了,但是因为更新的值是一样的,所以并没有修改到记录,Changed为0 Query OK, 0 rows affected (12.40 sec) Rows matched: 1  Changed: 0  Warnings: 0

#这边再查询一次,记录成功修改,是最新数据 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost |+--------------+|        3000 |+--------------+1 row in set (0.00 sec)

#这边查询结果是旧的,因为记录并没有被修改到,所以显示的也是事务开始时的数据 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost |+--------------+|        2000 |+--------------+1 row in set (0.00 sec)

#提交并退出事务 mysql> commit; Query OK, 0 rows affected (0.13 sec)

#这时就显示最新的数据了 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost |+--------------+|        3000 |+--------------+1 row in set (0.00 sec)

这是一个正常的情况,因为记录并没有被修改到,所以显示的也是事务开始时的数据,保证了RR级别的可重复读特性。

问题现象

下面来看另一个不正常的情况,环境是和上面一致的,没有改变,我们来直接看图:

可以看到,执行方式和上面一致,右边的事务等待了12秒后执行了,也就是左边commit之后。但是,变成了不可重复读,右边事务里面没有commit也可以看到最新提交的数据,甚是诡异。

解决方法

第一种方案:将隔离级别改成RC貌似是可以解决问题,但是解决的是左边的问题,把可重复读的特性改成了不可重复读了而已。这样两边都能查到已经提交的新数据。

#更改mysql全局隔离级别为RC

set global tx_isolation = 'READ-COMMITTED'

改了之后,全局都变成了不可重复读,并且没有了间隙锁,也正因为可以看到已经提交的新数据,所以上面正常的情况也会跟下面一致,但是不代表有问题,这本身就是RC隔离级别的特点。

然后有人说,这不是没解决问题嘛,只是把问题全部改成一样而已,好像是这样。所以就有第二种方案。

第二种方案:把binlog格式改成ROW,不用改隔离级别,问题是真的解决了。

#把全局binlog格式改成ROW格式

set global binlog_format = 'ROW';

在上面看到原始的的binlog格式是MIXED混合模式,现在改成ROW模式,再试一遍。

好了。一切正常了,这就是RR的特性,可重复读。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

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