数据库-MySQL-事务-事务隔离级别的可重复读是如何实现的?

MySQL 事务隔离级别中的“可重复读”(Repeatable Read)是如何实现的

在MySQL中,可重复读Repeatable Read)是默认的事务隔离级别,特别是在使用InnoDB存储引擎时。这个隔离级别通过多版本并发控制(MVCC)和锁机制,确保在同一事务中多次读取相同的数据时,结果是一致的。本文将详细介绍可重复读隔离级别的实现原理、与其他隔离级别的比较、可能遇到的并发问题及其解决方法,以及实际应用中的注意事项。

1. 事务隔离级别概述

在深入探讨可重复读之前,简要回顾一下事务隔离级别的基本概念。SQL标准定义了四种事务隔离级别:

  1. 读未提交(Read Uncommitted)
  2. 读已提交(Read Committed)
  3. 可重复读(Repeatable Read)
  4. 串行化(Serializable)

这些隔离级别通过控制事务之间的读写操作,平衡数据一致性和系统并发性能。

2. 可重复读(Repeatable Read)的定义

可重复读隔离级别的主要特性包括:

  • 防止脏读(Dirty Read):事务只能读取到其他事务已经提交的数据。
  • 防止不可重复读(Non-Repeatable Read):在同一事务中,多次读取同一数据行,结果一致,即使其他事务修改了该数据。
  • 防止幻读(Phantom Read):确保在事务期间,使用相同查询条件的多次查询结果集一致,防止其他事务在其间插入或删除满足查询条件的数据行。

相比于读已提交可重复读提供了更高的数据一致性保障,但也可能带来更多的锁竞争。

3. InnoDB 中的实现机制

InnoDB 通过多版本并发控制(MVCC)和锁机制来实现不同的隔离级别。在可重复读隔离级别下,其具体实现机制如下:

3.1. 多版本并发控制(MVCC)

MVCC 是 InnoDB 支持高并发和不同隔离级别的核心机制。它通过为每一行数据维护多个版本,使得不同的事务可以看到数据的不同状态,而无需相互阻塞。

可重复读隔离级别中,InnoDB 为整个事务生成一个Read View,该视图在事务开始时固定,保证事务中多次读取的快照数据一致。

3.2. Read View

Read View 是 InnoDB 用于确定数据版本可见性的机制。在可重复读隔离级别下:

  • 整个事务共享同一个 Read View,即事务开始时创建的快照。
  • 该 Read View 包含事务开始时活动的所有事务ID。
  • 查询操作基于该 Read View 决定哪些版本的数据对当前事务可见。

由于整个事务共享一个 Read View,在事务生命周期内读取的数据版本保持一致,即使其他事务提交了新的更改。

3.3. 数据版本和 Undo Log

InnoDB 通过 Undo Log 记录数据的旧版本。每当数据被修改时,旧版本的数据会保存在 Undo Log 中,供其他事务访问。

可重复读隔离级别中,当事务需要读取数据时:

  1. 读取时快照:事务依赖于创建时的 Read View,从 Undo Log 中提取符合条件的历史数据版本,确保多次读取结果一致。
  2. 避免脏读和不可重复读:由于使用固定的 Read View,事务不会看到其他未提交或之后提交的事务的更改。

3.4. 锁机制

虽然 MVCC 主要用于读操作的隔离,锁机制仍在写操作中发挥关键作用。InnoDB 使用以下几种锁来管理事务间的并发:

  • 行级锁(Row Locks):锁定特定的行,防止其他事务修改。
  • 意向锁(Intention Locks):表级锁,表明事务将对某些行加锁,优化锁管理。
  • 间隙锁(Gap Locks):锁定索引中的间隙,防止其他事务在该间隙内插入新的数据行,进而防止幻读。

可重复读隔离级别下,InnoDB 会更积极地使用间隙锁,以防止符合查询条件的新行被插入,确保幻读问题得到避免。

4. 可重复读与其他隔离级别的比较

4.1. 读未提交(Read Uncommitted)

  • 脏读:允许
  • 不可重复读:允许
  • 幻读:允许
  • 特点:最低的隔离级别,数据一致性差,但并发性高。

4.2. 读已提交(Read Committed)

  • 脏读:不允许
  • 不可重复读:允许
  • 幻读:允许
  • 特点:避免脏读,提高了一定的并发性,但数据一致性仍有欠缺。

4.3. 可重复读(Repeatable Read)

  • 脏读:不允许
  • 不可重复读:不允许
  • 幻读:不允许
  • 特点:通过 MVCC 和间隙锁,提供较高的数据一致性和并发性。

4.4. 串行化(Serializable)

  • 脏读:不允许
  • 不可重复读:不允许
  • 幻读:不允许
  • 特点:最高的隔离级别,所有事务串行执行,保证数据一致性,但并发性能最低。

5. 具体示例

下面通过一个具体示例来说明可重复读隔离级别在 InnoDB 中的表现。

场景描述

  • 事务 A事务 B 同时操作同一表的数据。
  • 初始状态:accounts 表中,user_id = 1balance1000

操作步骤

  1. 事务 A 开始,并在 可重复读 隔离级别下执行:

    START TRANSACTION;
    SELECT balance FROM accounts WHERE user_id = 1; -- 返回 1000
    
  2. 事务 B 开始,更新 user_id = 1balance

    START TRANSACTION;
    UPDATE accounts SET balance = balance + 500 WHERE user_id = 1;
    COMMIT;
    

    此时,user_id = 1balance 变为 1500,事务 B 提交。

  3. 事务 A 再次执行相同的查询:

    SELECT balance FROM accounts WHERE user_id = 1; -- 仍返回 1000
    COMMIT;
    

结果分析

  • 可重复读隔离级别下,事务 A 在整个事务过程中看到的数据版本保持一致,即使事务 B进行了更新并提交,事务 A 的第二次查询仍返回 1000
  • 这种行为避免了不可重复读现象,但需要注意,事务 A 可能未能看到事务 B的最新提交(取决于具体的查询类型和索引覆盖情况)。

防止幻读的示例

  1. 事务 A 开始,并在可重复读隔离级别下执行:

    START TRANSACTION;
    SELECT COUNT(*) FROM accounts WHERE balance > 500; -- 返回 1
    
  2. 事务 B 开始,插入一条新的记录满足查询条件:

    START TRANSACTION;
    INSERT INTO accounts (user_id, balance) VALUES (2, 600);
    COMMIT;
    
  3. 事务 A 再次执行相同的查询:

    SELECT COUNT(*) FROM accounts WHERE balance > 500; -- 仍返回 1
    COMMIT;
    

结果分析

  • 可重复读隔离级别下,事务 A 的第二次查询仍返回第一次的结果,未看到事务 B插入的新记录,防止了幻读现象。

6. 可重复读 的优缺点

优点

  • 数据一致性高:避免了脏读、不可重复读和幻读,确保事务内数据一致性。
  • 良好的并发性:通过 MVCC 和锁机制,提供较好的并发性能,适合大多数 OLTP 应用。

缺点

  • 锁竞争:为了防止幻读,InnoDB 使用间隙锁,可能增加锁竞争,影响性能。
  • 资源消耗:维护 Undo Logs 和 Read Views 需要额外的存储和计算资源,尤其在高并发环境下。

7. 实际应用中的选择

可重复读隔离级别适用于以下场景:

  • 需要高数据一致性的业务应用,如财务系统、库存管理等。
  • 中高并发的在线交易处理(OLTP)系统,既需要保证数据一致性,又要求较好的性能。
  • 需要避免幻读的复杂查询和更新操作场景。

然而,如果系统对并发性能有极高要求,且可以容忍一定的数据不一致性,可以考虑降低隔离级别(如读已提交)。反之,如果业务需要更严格的数据一致性保障,可以选择更高的隔离级别(如串行化),尽管这可能带来更高的锁竞争和性能开销。

8. 配置和优化

8.1. 设置事务隔离级别

在 MySQL 中,可以通过以下命令设置全局或会话级别的事务隔离级别:

  • 设置全局隔离级别为可重复读

    SET GLOBAL transaction_isolation = 'REPEATABLE-READ';
    
  • 设置当前会话的隔离级别为可重复读

    SET SESSION transaction_isolation = 'REPEATABLE-READ';
    
  • 查看当前隔离级别

    SELECT @@global.transaction_isolation;
    SELECT @@session.transaction_isolation;
    

8.2. 优化建议

  • 合理设计索引:确保查询操作有合适的索引支持,减少全表扫描,降低锁定的行数和范围,减少锁竞争。
  • 控制事务长度:尽量缩短事务的执行时间,避免长事务持有锁资源,减少锁等待和死锁的可能性。
  • 批量处理和分批提交:对于大量数据的操作,可以考虑分批处理和分批提交,降低单个事务的锁持有时间。
  • 监控和分析锁情况:使用工具(如 SHOW ENGINE INNODB STATUSPerformance Schema)监控锁等待、死锁等情况,及时优化慢查询和高锁竞争的操作。

8.3. 避免长时间持有事务

长时间持有事务可能导致大量的锁资源被占用,影响系统的并发性能。建议:

  • 在应用层合理管理事务:尽量避免在用户等待输入或处理逻辑时持有事务,确保事务尽快提交或回滚。
  • 分解复杂事务:将复杂的业务操作分解为多个小事务,降低单个事务的资源消耗和锁竞争。

9. 总结

MySQL 中的“可重复读”隔离级别通过多版本并发控制(MVCC)和锁机制,实现了事务内多次读取数据的一致性,防止了脏读、不可重复读和幻读。其具体实现包括:

  • Read View:在事务开始时创建,确保整个事务期间数据读取的一致性。
  • Undo Log:存储数据的历史版本,供事务根据 Read View 读取一致的数据快照。
  • 锁机制:使用行级锁、意向锁和间隙锁,管理事务间的并发访问,防止幻读。

可重复读隔离级别在保障数据一致性的同时,仍提供较好的并发性能,适用于大多数需要高数据一致性和并发性的应用场景。然而,开发者需要注意锁竞争和事务设计,以充分发挥其优势并避免潜在的性能瓶颈。

在实际应用中,理解并合理配置事务隔离级别,对于确保数据库系统的正确性、性能和可靠性至关重要。选择合适的隔离级别,应综合考虑业务需求、数据一致性要求和系统的并发性能,做出最优的决策。

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

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

相关文章

【中间件快速入门】什么是Redis

现在后端开发会用到各种中间件,一不留神项目可能在哪天就要用到一个我们之前可能听过但是从来没接触过的中间件,这个时候对于开发人员来说,如果你不知道这个中间件的设计逻辑和使用方法,那在后面的开发和维护工作中可能就会比较吃…

金晟新能源由盈转亏:毛利率下滑产能利用率不佳,关联交易持续增加

《港湾商业观察》黄懿 近期,广东金晟新能源股份有限公司(下称“金晟新能源”)递交了招股书,拟冲刺港交所IPO,中金公司、招银国际为联席保荐人。 金晟新能源处于电池回收的新兴大势行业,但是,受…

RTMP|RTSP播放器只解码视频关键帧功能探讨

技术背景 我们在做RTMP|RTSP直播播放器的时候,遇到过这样的技术诉求,在一些特定的应用场景中,可能只需要关键帧的信息,例如视频内容分析系统,可能只对关键帧进行分析,以提取特征、检测对象或场景变化。鉴于…

2K高刷电竞显示器怎么选?

2K高刷电竞显示器怎么选?哪个价格适合你?哪个配置适合你呢? 1.HKC G27H2Pro - 2K高刷电竞显示器怎么选 外观设计 - HKC G27H2Pro 2K高刷电竞显示器 电竞风拉满:作为猎鹰系列的一员,背部 “鹰翼图腾” 切割线搭配炎红…

STM32-时钟树

STM32-时钟树 时钟 时钟

基于SpringBoot+WebSocket的前后端连接,并接入文心一言大模型API

前言: 本片博客只讲述了操作的大致流程,具体实现步骤并不标准,请以参考为准。 本文前提:熟悉使用webSocket 如果大家还不了解什么是WebSocket,可以参考我的这篇博客: rWebSocket 详解:全双工…

StarRocks BE源码编译、CLion高亮跳转方法

阅读SR BE源码时,很多类的引用位置爆红找不到,或无法跳转过去,而自己的Linux机器往往缺乏各种C依赖库,配置安装比较麻烦,因此总体的思路是通过CLion远程连接SR社区已经安装完各种依赖库的Docker容器,进行编…

STM32 按键密码系统的实现

本次基于STM32F407开发板,来实现密码系统,输入四位密码,密码正确时LED1亮,密码错误时四个LED灯双闪。 LED双闪代码 简单的逻辑,让四个LED灯先亮然后再延时一会LED灯灭,循环4此实现双闪的效果。 按键密码的…

linux常用加固方式

目录 一.系统加固 二.ssh加固 三.换个隐蔽的端口 四.防火墙配置 五.用户权限管理 六.暴力破解防护 七.病毒防护 八.磁盘加密 九.双因素认证2FA 十.日志监控 十一.精简服务 一.系统加固 第一步:打好系统补丁 sudo apt update && sudo apt upgra…

hadoop==docker desktop搭建hadoop

hdfs map readuce yarn https://medium.com/guillermovc/setting-up-hadoop-with-docker-and-using-mapreduce-framework-c1cd125d4f7b 清理资源 docker-compose down docker system prune -f

【Elasticsearch 基础入门】Centos7下Elasticsearch 7.x安装与配置(单机)

Elasticsearch系列文章目录 【Elasticsearch 基础入门】一文带你了解Elasticsearch!!!【Elasticsearch 基础入门】Centos7下Elasticsearch 7.x安装与配置(单机) 目录 Elasticsearch系列文章目录前言单机模式1. 安装 J…

Fullcalendar @fullcalendar/react 样式错乱丢失问题和导致页面卡顿崩溃问题

问题描述: 我使用 fullcalendar的react版本时,出现了一个诡异的问题,当我切换到 一个iframe页面时(整个页面是一个iframe嵌入的),再切换回来日历的样式丢失了!不仅丢失了样式还导致页面崩溃了&…

算法12(力扣739)-每日温度

1、问题 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。 2、示例 &#…

STM32项目分享:智能厨房安全检测系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: STM32智能厨房安全检测系统 (资料分…

定时器按键tim_key模版

低优先级放在高优先级内势必是程序卡死 把高优先级放到低优先级内,会使程序卡死 可修改 Debuger调试方法 Pwm rcc #include "my_main.h" uint8_t led_sta0x10; char text[30]; void LED_Disp(uint8_t dsLED) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPI…

大模型-本地化部署调用--基于ollama+openWebUI+springBoot

大模型-本地化部署调用–基于ollamaopenWebUIspringBoot 前言 前段时间,啊,可能不是前段时间,过去的2024年吧,大模型这块的内容也是非常火的,各家巨头也开始卷大模型的研发。那么本人呢也在过去的一年中也是用到了一…

RV1126+FFMPEG推流项目源码

源码在我的gitee上面,感兴趣的可以自行了解 nullhttps://gitee.com/x-lan/rv126-ffmpeg-streaming-projecthttps://gitee.com/x-lan/rv126-ffmpeg-streaming-project

宏_wps_宏修改word中所有excel表格的格式_设置字体对齐格式_删除空行等

需求: 将word中所有excel表格的格式进行统一化,修改其中的数字类型为“宋体, 五号,右对齐, 不加粗,不倾斜”,其中的中文为“宋体, 五号, 不加粗,不倾斜” 数…

ServletOutputStream failed to write: Broken pipe

案发现场 问题: org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to write: Broken pipe org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream …