mysql-分析并解决可重复读隔离级别发生的删除幻读问题

news/2024/11/25 14:55:30/

在 MySQL 的 InnoDB 存储引擎中,快照读和当前读的行为会影响事务的一致性。让我们详细分析一下隔离级别味可重复读的情况下如何解决删除带来的幻读。
场景描述
假设有一个表 orders,其中包含以下数据:
在这里插入图片描述
事务 A 执行快照读

START TRANSACTION;
SELECT * FROM orders WHERE customer_id = 200; -- 快照读

事务 B 执行当前读并删除记录

START TRANSACTION;
DELETE FROM orders WHERE id = 10; -- 当前读,尝试删除
COMMIT;

分析

  • 快照读(事务 A)
  • 快照读:事务 A 执行的是快照读,它基于事务开始时的数据快照,不加锁。
  • 数据快照:事务 A 会看到事务开始时的数据快照,即 customer_id = 200 的记录为 (3, 200, 150) 和 (10,200, 250)。
  • 当前读(事务 B)
  • 当前读:事务 B 执行的是当前读操作,它会尝试获取 id = 10 的记录的行锁。
  • 删除操作:事务 B 成功删除 id = 10 的记录,并提交事务。

影响分析
事务 A 第一次查询:
事务 A 查询 customer_id = 200 的记录,结果为 (3, 200, 150) 和 (10, 200, 250)。
事务 B 删除记录:
事务 B 删除 id = 10 的记录,并提交事务。
事务 A 第二次查询:
事务 A 再次查询 customer_id = 200 的记录,结果为 (3, 200, 150),缺少了 (10, 200, 250)。

结论
幻读:这是因为事务 B 在事务 A 之间删除了一条记录。

解决方案
使用可重复读(Repeatable Read)隔离级别 + 间隙锁

1.设置隔离级别:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

2.使用当前读操作:

  • 在事务 A 中,使用 SELECT … FOR UPDATE 或 SELECT … FOR SHARE 来获取行锁和间隙锁。
  • 这样可以确保在事务 A 的整个生命周期内,查询结果保持一致。

示例
事务 A 执行以下操作:

START TRANSACTION;
SELECT * FROM orders WHERE customer_id = 200 FOR UPDATE; -- 当前读,加锁并获取间隙锁
-- 进行业务逻辑处理
SELECT * FROM orders WHERE customer_id = 200; -- 再次查询
COMMIT;

事务 B 执行以下操作:

START TRANSACTION;
DELETE FROM orders WHERE id = 10; -- 当前读,尝试删除
COMMIT;

由于事务 A 持有 customer_id = 200 范围内的所有记录的行锁和间隙锁,事务 B 的删除操作将被阻塞,直到事务 A 提交或回滚。这样可以确保事务 A 的查询结果在整个事务期间保持一致。

总结
当前读:事务 A 第一次执行的时候使用的是当前读因此会对该行进行加锁,所以其他事务无法对该行进行删除或者更新操作。
快照读:事务 A 第二次执行的时候此时事务并未提交因此使用快照读仍然能读取到该行。
当前读:事务 B 执行当前读并删除记录,由于事务 A 持有锁,导致事务B处于阻塞状态直到事物A释放 。


http://www.ppmy.cn/news/1549844.html

相关文章

docker-compose 安装 pgsql (postgres)

docker-compose-pg.yml 文件内容 version: 3 services:iepms-gateway:image: postgres:14.13container_name: postgresql-14.13restart: alwaysprivileged: trueenvironment:- POSTGRES_PASSWORD: test2024ports:- 15432:5432volumes:- /home/iepms/data/pgsql/data:/var/lib/…

(笔记,自己可见_1)简单了解ZYNQ

1、zynq首先是一个片上操作系统(Soc),结合了arm(PS)和fpga(PL)两部分组成 Zynq系统主要由两部分组成:PS(Processing System)和PL(Programmable L…

前端知识点---箭头函数(javascript)

文章目录 箭头函数(javascript)箭头函数省略小括号省略大括号箭头函数与没有argumentsthis的指向问题 箭头函数(javascript) 箭头函数 引子: <input type"text" id"txt1" ><input type"button" id"btn" value"测试&…

Leetcode打卡:最小区间

执行结果&#xff1a;通过 题目&#xff1a;632 最小区间 你有 k 个 非递减排列 的整数列表。找到一个 最小 区间&#xff0c;使得 k 个列表中的每个列表至少有一个数包含在其中。 我们定义如果 b-a < d-c 或者在 b-a d-c 时 a < c&#xff0c;则区间 [a,b] 比 [c,d] …

cocos creator 3.8 打飞机Demo 9

简单的demo实现&#xff0c;没优化以及加上音频文件&#xff0c;没有开始结束暂停等逻辑。 首先2D状态下&#xff0c;接受的素材 1、首先实现背景的移动 基本逻辑如下 关于fixUpdate&#xff0c;可以写一个基类&#xff0c;然后继承它 //固定帧计时private _now_time 0;//固定…

RHCE——DNS域名解析服务器

1、DNS简介 DNS是互联网上的一项服务&#xff0c;它作为将域名和IP地址相互映射的一个分布式 数据库&#xff0c;能够使人更方便的访问互联网。 &#xff08;1&#xff09;因特网的域名结构 因特网在命名时采用的是层次树状结构的命名方法。任何一个连接在 因特网上的主机或路…

Python MySQL通过Binlog 获取变更记录 恢复数据

通过MySQL的二进制日志&#xff08;Binlog&#xff09;获取数据库的变更记录&#xff0c;并用于恢复数据&#xff0c;是一个相对高级的操作。这通常涉及读取Binlog中的事件&#xff0c;解析这些事件以了解数据变更的详细信息&#xff0c;然后基于这些信息来恢复或回滚数据。 在…

设计模式之 命令模式

命令模式&#xff08;Command Pattern&#xff09;是行为型设计模式之一&#xff0c;它将请求&#xff08;或命令&#xff09;封装成一个对象&#xff0c;从而使用户能够将请求发送者与请求接收者解耦。通过命令模式&#xff0c;调用操作的对象与执行操作的对象不直接关联&…