当前位置: 首页 > news >正文

MySQL RR (Repeatable Read) 隔离级别规则细节

准备

测试表:

CREATE TABLE `transaction_test`
(`id`    int,`value` int,`mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE = InnoDB;

mysql设置:

transaction_isolation = REPEATABLE-READ
autocommit = ON

事务指令:

BEGIN  开启事务
COMMIT  提交
ROLLBACK  回滚

1:事务基础

A B两个连接

A:
BEGIN;
insert into transaction_test(id, value) values (1, 1);B:
select * from transaction_test where id = 1;   
-- 查不到未提交的修改A:
COMMIT;B:
select * from transaction_test where id = 1;   
-- 能查到已提交的修改,mtime是执行insert时的时间

2:读操作,快照读

A:
insert into transaction_test(id, value) values (1, 1);B:
BEGIN;
select * from transaction_test where id = 1 or id = 2;
-- 查到id=1A:
insert into transaction_test(id, value) values (2, 2);B:
select * from transaction_test where id = 1 or id = 2;
--仍只查到id=1
--RR是读快照,第一次select时为整个库创建一致性快照,后续select都基于这个快照
--即创建快照后,其他事务的写操作(增、删、改)均对本次事务不可见

3:写操作,当前读,幻读

A:
BEGIN;
select * from transaction_test where id = 1;
--返回空B:
insert into transaction_test(id, value) values (1, 1);A:
select * from transaction_test where id = 1;
--返回空,为第一次select时的快照update transaction_test set value = 2 where id = 1;
--1 row affected ,写操作会取当前已commit的数据版本(即当前读,而非快照读),所以能修改 B insert 的数据select * from transaction_test where id = 1;
--查到id=1,自己事务的写操作对自己可见,所以此时能看到id=1这行数据
--上次查询读不到id=1的行,本次能读到,这一问题称为幻读
--注意:如果上述 update 改为 set value = 1,不改变数据的值,则后续仍然读不到

4:SELECT 后 INSERT 的竞态条件

A:
BEGIN;
select * from transaction_test where id = 1;
-- 返回空B:
insert into transaction_test(id, value) values (1, 1);A:
-- 检查select结果是否存在,如果不存在,执行插入
insert into transaction_test(id, value) values (1, 1);
-- Duplicate entry '1' for key 'PRIMARY'   插入失败

5:更新丢失

A:
BEGIN;
SELECT value FROM transaction_test WHERE id = 1; -- 读快照,得到100B:
BEGIN;
SELECT value FROM transaction_test WHERE id = 1; -- 读快照,仍为100A:
UPDATE transaction_test SET value = 100 + 10 WHERE id = 1; -- 写为110
COMMIT;B:
UPDATE transaction_test SET value = 100 + 20 WHERE id = 1; -- 写为120
COMMIT;

6:无丢失更新,排他锁

-- value初始为100
A:
UPDATE transaction_test SET value = value + 10 WHERE id = 1; 
-- 写为110,UPDATE会加排他锁(X Lock),为行锁B:
UPDATE transaction_test SET value = value + 20 WHERE id = 1;
-- 此时A持有id=1的行锁,B等待A:
COMMIT;  
-- 提交value=110的值B:
--A提交会释放锁,此时重新执行B的UPDATE,写操作为当前读,value由110更新为130
COMMIT;
-- 提交value=130的值

7:间隙锁,避免幻读

A:
BEGIN;
select * from transaction_test where id < 5 for update;
--执行 SELECT ... FOR UPDATE 或 UPDATE、DELETE 语句时,会为条件涉及的范围加间隙锁(Gap Lock)
--即使范围中没有实际数据,也会锁定间隙。B:
insert into transaction_test(id, value) values (1, 1);
--尝试在锁定范围(id=1)内写数据,会阻塞A:
-- 检查select结果是否存在,如果不存在,执行插入
insert into transaction_test(id, value) values (1, 1);
--插入成功
commitB:
--A commit 释放锁,此时重新执行B的插入,插入失败

8:死锁检测

InnoDB死锁检测默认开启,innodb_deadlock_detect=ON

A:
BEGIN;
update transaction_test set value = 1 where id = 1;
-- 持有id=1的行锁B:
BEGIN;
update transaction_test set value = 4 where id = 2;
-- 持有id=2的行锁A:
update transaction_test set value = 2 where id = 2;
-- 阻塞,等待事务B的锁
COMMIT;B:
update transaction_test set value = 3 where id = 1;
-- 阻塞,等待事务A的锁  -> 死锁
-- 当检测到死锁时,InnoDB 会主动回滚代价最小的事务,打破循环等待
-- 此时B回滚,A执行成功,回滚的事务会收到 ERROR 1213: Deadlock found
COMMIT;

其他事务规则:

  • BEGIN 后再次执行 BEGIN:
    当前活跃的事务会被隐式提交,并开启一个新事务
  • BEGIN 后未提交事务就直接关闭客户端连接:
    MySQL 会自动回滚该事务
  • AUTO_INCREMENT:
    自增ID的值一旦生成,即使事务回滚也不会回退
http://www.xdnf.cn/news/227863.html

相关文章:

  • 【计算机视觉】目标检测:深度解析Detectron2:Meta开源目标检测与图像分割框架实战指南
  • Linux Nginx网站服务【完整版】
  • 从高端制造到民生场景:天元轻量化软件的“破局”之路
  • 【QT】编写第一个 QT 程序 对象树 Qt 编程事项 内存泄露问题
  • 大语言模型 06 - 从0开始训练GPT 0.25B参数量 - MiniMind 实机配置 GPT训练基本流程概念
  • ASP.NET MVC​ 入门与提高指南六
  • 一套SaaS ERP管理系统源码,支持项目二开商用,SpringBoot+Vue+ElementUI+UniAPP
  • 11.Spring Boot 3.1.5 中使用 SpringDoc OpenAPI(替代 Swagger)生成 API 文档
  • 若依Vue + Spring Boot:前后端参数传递实践与 @RequestParam、@RequestBody、@ModelAttribute 使用详解
  • 解决vscode cmake提示检测到 #include 错误
  • 【Hive入门】Hive高级特性:事务表与ACID特性详解
  • Ubuntu 24.04 终端美化
  • 第一章 OpenCV篇-配置及基础知识-Python
  • 常用开发脚本工具推荐
  • java网络原理5
  • 【C++】数据结构 九种排序算法的实现
  • python对接马来西亚股票完整代码
  • 微前端框架选型指南
  • Go并发控制模式:基于Channel的实践与优化
  • Github 2025-04-30 C开源项目日报 Top10
  • 3dgs渲染 Nvdiffrast
  • getattr 的作用
  • 6.应用层
  • 搭建PCDN大节点,服务器该怎么配
  • Vue3 后台管理系统模板
  • redis 数据类型新手练习系列——List类型
  • 驱动开发系列54 - Linux Graphics QXL显卡驱动代码分析(一)设备初始化
  • 微信小程序 XSS 防护知识整理
  • HTML ASCII 编码详解
  • 遗传算法(Genetic Algorithm,GA)