关系型数据库的数据隔离级别Read Committed与Repeatable Read

news2025/2/24 3:40:52

一、背景

数据库隔离级别会影响到我们的查询,本文试图以生产中的示例,给你一个直观的认识。

所谓,理论要结合实践,才能让我们理解得更加透彻。

另外,隔离级别的知识面很大,本文也不可能俱全,下面给出本文要阐述的目标:

二、目标

  • Read Committed与Repeatable Read的区别
  • 实际编程中的使用场景
  • 什么是Phamtom
  • 什么是Write Skew

三、隔离级别

1、可重复读

可以重复读的意思是,在同一个事务中,多次读取同一条记录,返回的数据是相同的;不会因为其他的事务修改它而变化。

必须要先理解这个默认隔离级别,才好反过来理解读已提交的级别。

最后,在你实际的应用中,要决定是否降低隔离级别。(以我实际的使用经验看,降低到读已提交级别,不仅符合程序的要求,而且提升了数据库的性能)
我们都知道,隔离级别越低,数据库的读写性能就越高,所谓“鱼与熊掌不可兼得”~~

下面摘引一个示例:

-- 事务A查询主键ID=7的姓名,返回是Aaron
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

-- 事务B查询主键ID=7的姓名,返回是Aaron
-- 随后,把它修改为Bob,最后提交事务
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

-- 事务A二次查询主键ID=7的姓名,返回仍然是Aaron
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session1> COMMIT;

上述的过程与结论好理解,在实际编程中,你一定要考虑,现实场景会是需要如此吗?

如果更新换成账户余额、库存和积分等变化频繁的场景呢。。。

把问题先留在这里,我们继续另外一个问题:

  • 因为 Phamtom 而导致的 Write Skew现象

再举一个示例:
在这里插入图片描述
重复演示一遍,什么是可重复读的隔离级别。。

那么怎么会导致幻影Phamtom呢?

所谓幻影是指第一次查询的时候没有它,而更新的时候,却把它更新成功了。

在这里插入图片描述
事务A,期望是更新Alice/Bob/Carol这三个人的积分+1
当事务B,新增了一个人Frank,其积分也大于740。
结果,事务A按更新条件(score > 740)执行,导致不在期望中的Frank也被更改了。

这就是Write Skew。
换句话说,可重复读,虽然可以避免查询的可重复,但是它解决不了幻影带来的写倾斜Write Skew。

  • 怎么解决幻影现象
    批量更新记录,更新条件是上一步查询出来的记录ID集合。
select * from gamer where score >= 740;
# 100
# 101
# 102
# 103
update gamer a set a.credit = credit + 1 where a.id in (100,101,102,103);

-- 不要使用区间比较
update gamer a set a.credit = credit + 1 where a.score >= 740;

2、读已提交

和可重复读相比,它会读取到其他事务提交的记录。

这里,以第一个示例进行修改举例。

-- 事务A查询主键ID=7的姓名,返回是Aaron
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

-- 事务B查询主键ID=7的姓名,返回是Aaron
-- 随后,把它修改为Bob,最后提交事务
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

-- 事务A二次查询主键ID=7的姓名,返回变成了Bob
session1> SELECT firstname FROM names WHERE id = 7;
Bob
session1> COMMIT;

同一个事务的两次相同查询,返回的记录会因为其他事务的提交而变化。

那么它的适用场景是什么呢?

  • sql乐观锁更新的自旋

sql乐观锁更新,不外乎以下两种写法:

-- version机制, 先查询出version, 每次更新记录的时候,version值自动加1
select version as old_version from gamer where id = 101;
# 1
int new_score = 1000;
update gamer a set a.score = {new_score}, a.version = a.verson + 1 
where id = 101 and version={old_version}
-- 实际执行语句:
update gamer a set a.score = 1000, a.version = a.verson + 1 
where id = 101 and version=1;


-- 更新条件, 将查询出来的score作为查询条件,保证在更新的时候,被更新的值是前面查询出来的值。
select score as old_score from gamer where id = 101;
# 980

int new_score = 1000;
update gamer a set a.score={new_score} where id = 101 and score={old_score};
-- 实际执行语句:
update gamer a set a.score=1000 where id = 101 and score=980;

这里有一个问题,如果更新的并发度比较大的时候,会出现频繁的更新失败。
所以,建议你在更新的外围,使用一个自旋。

下面是一个java语言实现的伪代码:

// 自旋3次
boolean flag = false;
int newScore = 1000;
for (int i = 0; i < 3; i++)
{
    // 每次自旋,都再次查询数据库,因为其他事务可能修改该记录。所以隔离级别必须是读已提交。
    // 如果是可重复读,这里的自旋就没有任何意义。
   Game game = gameService.findById(101);

   falg = gameService.update(game.getScore(), game.getId(), newScore);
   //或者 falg = gameService.update(game.getScore(), game.getId());

   // 更新成功,提前退出
   if (flag) {
     break;
   }
}

四、查询和设置事务隔离级别

show variables like 'transaction_isolation';
show variables like 'tx_isolation';

在这里插入图片描述

-- 设置全局事务级别为 READ-COMMITTED
set global transaction isolation level read committed;

阿里云的RDS,支持修改该参数,不过需要重启生效。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1285996.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据SpringBoot项目|基于SpringBoot+MyBatis框架健身房管理系统的设计与实现

大数据SpringBoot项目|基于SpringBootMyBatis框架健身房管理系统的设计与实现 摘 要:本文基于Spring Boot和MyBatis框架&#xff0c;设计并实现了一款综合功能强大的健身房管理系统。该系统涵盖了会员卡查询、会员管理、员工管理、器材管理以及课程管理等核心功能&#xff0c;…

理解js中原型链的封装继承多态

前言 面向对象有三大特性:封装继承多态。 不过,js和java的封装继承多态是不一样的,我和从事java开发的朋友有过一次对话(抬杠 !--)。 我说:javascript也是面向对象语言, 他说:不对吧,js不是面向对象吧。 我说:是的,官方说的就是面向对象语言。 他说:那你知道三大特性吗?…

彼此的远方

那天两个人互相表白了心意&#xff0c;在那天那刻确定了彼此相爱&#xff0c;没有鲜花&#xff0c;没有礼物。 男孩的世界曾陷入黑暗&#xff0c;冷清而又孤寂&#xff0c;女孩带着光和热来了&#xff0c;后来&#xff0c;女孩成为了男孩的太阳。女孩以为男孩是远方的风…

SpringBoot 注入RedisTemplat 启动报错

需求 因为需要限制部门内多个人员同一时间操作同一批客户的需求&#xff0c;考虑下决定用Redis滑动窗口实现自过期以及并发校验。 问题 新建了个Redis工具类封装RedisTemplat 操作&#xff0c;到启动时却发现无法正常启动&#xff0c;报错注入错误。 The injection point has…

数字化转型:互联网+为企业带来的全新机遇

引言 在当今快速发展的商业环境中&#xff0c;数字化转型和互联网已成为企业前进的关键动力和重要战略。数字化转型代表了企业在数字技术的推动下&#xff0c;对其运营模式、业务流程以及客户体验的全面变革和升级。而“互联网”则突显了数字化时代与传统产业的融合&#xff0…

RAR文件的密码保护如何设置和取消?

RAR文件是压缩包一种常用的压缩文件格式&#xff0c;对于这种文件&#xff0c;我们如何设置和取消密码保护呢&#xff1f; 首先我们要下载适用于RAR文件的WinRAR解压缩软件&#xff0c;然后在压缩文件的时候&#xff0c;就可以同步设置密码&#xff0c;选中需要压缩的文件&…

navicat premium 历史版本下载地址

navicat贴心地给大家准备了一致的下载地址&#xff1a; 只是没有把旧版本的链接放出来而已。 链接的格式 &#xff1a; 前缀版本类型语言位数 前缀&#xff1a;http:/download.navicat.com/download/navicat 版本&#xff1a;三位数&#xff0c;前两位是大版本&#xff0c;后…

微信小程序之猜数字和猜拳小游戏

目录 效果图 app.json 一、首页&#xff08;index3&#xff09;的代码 wxml代码 wxss代码 二、猜数字页面&#xff08;index&#xff09;代码 wxml代码 wxss代码 js代码 三.游戏规则页面&#xff08;logs&#xff09;代码 wxml代码 wxss代码 四.猜拳页面&#xff…

软件设计模式原则(五)接口隔离原则

顾名思义&#xff0c;该原则说的是&#xff1a;客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。 一.定义 核心思想&#xff1a; 使用多个专门的接口比使用单一的总接口要好。一个类对另外一个类的依赖性应当是建立在最小的接口上的。一个接口…

Leetcode题库(数据库合集)_ 难度:困难

目录 难度&#xff1a;困难1. 部门工资前三高的所有员工2. 行程和用户3. 体育馆的人流量4. 员工薪水的中位数5. 同一天的第一个电话和最后一个电话6. 查询员工的累计薪水7. 给定数字的频率查询中位数8. 学生地理信息报告9. Hopper 公司查询 ①10. 职员招聘人数11. 职员招聘人数…

【AXI死锁】

单主机单从机死锁 AXI4没有WID,所以比较严格,即写数据通道的数据必须严格的按照写地址通道的数据顺序传送,比如AW通道发送ADDR0,ADDR1,ADDR2三笔写操作,每个写操作burst length=2,那么W通道的顺序在AXI4协议的规定下必须为:WDATA0_0,WDATA0_1,WDATA1_0,WDATA1_1,WDATA2_0…

Linux last命令教程:如何查看用户的登录和注销历史(附案例详解和注意事项)

Linux last命令介绍 last命令在Linux中用于显示自文件/var/log/wtmp创建以来所有用户的登录和注销列表。可以给出一个或多个用户名作为参数&#xff0c;以显示他们的登录&#xff08;和注销&#xff09;时间和主机名。 Linux last命令适用的Linux版本 last命令在大多数Linux…

不知道如何制作电商产品说明书?推荐一个很好的方法!

作为一名电商从业者&#xff0c;你可能会经常面临一个问题&#xff1a;如何制作一份详细且吸引人的产品说明书&#xff1f;这的确是一个棘手的问题&#xff0c;因为产品说明书不仅要准确地描述产品的特点和功能&#xff0c;还要能够吸引潜在客户的注意。 一、电商网站制作产品说…

七、三台虚拟机JDK环境安装

目录 1、在三台机器上分别创建安装目录

一套rk3588 rtsp服务器推流的 github 方案及记录 -01

我不生产代码&#xff0c;我只是代码的搬运工&#xff0c;相信我&#xff0c;看完这个文章你的图片一定能变成流媒体推出去。 诉求&#xff1a;使用opencv拉流&#xff0c;转成bgr数据&#xff0c;需要把处理后的数据&#xff08;BGR&#xff09;编码成264&#xff0c;然后推流…

第三方支付原理

1.什么是第三方支付 所谓第三方支付&#xff0c;就是一些和各大银行签约、并具备一定实力和信誉保障的第三方独立机构提供的交易支持平台。在通过第三方支付平台的交易中&#xff0c;买方选购商品后&#xff0c;使用第三方平台提供的账户进行货款支付&#xff0c;由第三方通知卖…

微信小程序基础

1.小程序发展史 微信小程序之前&#xff0c;是使用weixin-sdk进行开发&#xff0c;调用视频&#xff0c;摄像头等。 微信小程序weixin up端&#xff0c;所以PC端的window这些没有&#xff0c;运行环境是IOS&#xff0c;安卓等&#xff0c;有一些特殊的调用录音功能&#xff0…

百元开放式蓝牙耳机哪款好、热门高性价比开放式推荐

在众多耳机类型中&#xff0c;开放式耳机正逐渐崭露头角。它们融合了音质和佩戴舒适性&#xff0c;能给你带来全新的佩戴感受。这些耳机不仅提供高品质的音响体验&#xff0c;还让你能够在户外佩戴欣赏音乐的同时保持对周围环境的感知&#xff0c;更加安全、保障。 在本文中&a…

分布式版本管理系统---->Git(Linux---centos(保姆式)讲解1)

文章目录: 1:什么是Git以及作用 2.Git的基本操作过程(创建git仓库,配置仓库的配置) 3.git的工作区&#xff0c;暂存区&#xff0c;版本库的关系 4.将文件添加到版本库&#xff1a;git add 与git commit -m命令 5.git log查看日志的引入 6.查看.git文件中的内容 7.修改文件内容查…

从浅入深掌握进阶结构体(C语言)

前言 这一期我们将继续讲解结构体的知识&#xff0c;还没有看过上一期的小伙伴一定要赶紧去学习哦。 上一期&#xff0c;冲鸭&#xff01; 那么话不多说我们开始今天的学习吧&#xff01; 文章目录 1,结构体的自引用2,匿名结构体3,位段4,结构体的传参5,尾声 1,结构体的自引用 …