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

MySQL中的事务隔离全详解

第一部分:MySQL事务的特性与并行事务引发的问题

1. 什么是事务及其四大特性(ACID)?

        事务(Transaction)是数据库操作的基本单位,它将一组操作组合在一起,以确保这些操作作为一个整体被执行。如果事务中的某个操作失败,所有的更改都会回滚(撤销),保证数据的完整性和一致性。

        事务的四大特性,通常用 ACID(Atomicity, Consistency, Isolation, Durability)来表示:

  1. 原子性(Atomicity)

    • 定义:事务是一个不可分割的整体,要么全部执行,要么全部不执行。
    • 举例:银行转账时,假设从账户 A 转账 100 元到账户 B,包括两个操作:
      1. 从 A 减少 100 元。
      2. 向 B 增加 100 元。
        如果任意一个操作失败,整个事务都必须回滚,确保账户余额不会出现错误。
  2. 一致性(Consistency)

    • 定义:事务执行前后,数据库都必须保持一致的状态。这意味着,所有事务必须从一个有效的数据库状态转到另一个有效的状态。
    • 举例:假设 A 和 B 的账户总余额为 1000 元,无论转账操作发生何种中断,事务的完成后,总余额必须仍然是 1000 元。
  3. 隔离性(Isolation)

    • 定义:多个事务并发执行时,一个事务的执行不能受到其他事务的干扰。每个事务就像独立运行在数据库中一样,其执行过程对其他事务是不可见的。
    • 举例:如果 A 向 B 转账时,另一个事务查询账户 B 的余额,必须等到转账事务完成后才能看到更新后的数据,否则查询的结果可能不准确。
  4.  持久性(Durability)

    • 定义:事务一旦提交,其所做的更改就会永久存储在数据库中,即使系统发生故障也不会丢失。
    • 举例:如果银行系统发生断电,但 A 转账给 B 的操作已经提交,那么重启后,转账操作仍然有效,数据不会丢失。

2. 并行事务可能引发的问题

        在并发环境中,多个事务同时操作数据库,可能导致以下问题:

  1. 脏读(Dirty Read)

    • 定义:一个事务读取了另一个事务未提交的数据。
    • 场景
      • 事务 A 修改了账户 B 的余额,将其从 500 元改为 300 元,但尚未提交。
      • 事务 B 读取了账户 B 的余额为 300 元。
      • 如果事务 A 回滚,账户 B 的余额又恢复到 500 元,此时事务 B 的读取结果就不正确了。
  2. 不可重复读(Non-Repeatable Read)

    • 定义:一个事务在两次读取同一数据时,发现数据不一致,数据被其他事务修改了。
    • 场景
      • 事务 A 查询账户 B 的余额,第一次读到 500 元。
      • 事务 B 修改账户 B 的余额为 300 元并提交。
      • 事务 A 再次读取账户 B 的余额,发现变成了 300 元,数据与第一次读取不一致。
  3. 幻读(Phantom Read)

    • 定义:一个事务在读取某个范围的数据时,发现范围内的数据被其他事务插入或删除了,导致前后查询结果不一致。
    • 场景
      • 事务 A 查询工资大于 5000 的员工数,第一次查到 5 个员工。
      • 事务 B 插入了一名工资为 6000 的新员工并提交。
      • 事务 A 再次查询,发现工资大于 5000 的员工变成了 6 个,出现了“幻影”记录。

第二部分:MySQL的事务隔离级别及其实现

        为了解决并发事务引发的问题,SQL 标准定义了 四种事务隔离级别,MySQL 也提供了相应的支持。隔离级别由低到高分别是:

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

1. 什么是事务隔离级别?

        事务隔离级别决定了一个事务能看到其他事务所做更改的程度。隔离级别越高,事务之间的干扰越少,但性能可能受到影响。

        MySQL 默认使用的存储引擎 InnoDB 实现了所有隔离级别,通过锁机制和多版本并发控制(MVCC)来实现隔离。

2. 四种隔离级别的详细介绍

1. 读未提交(Read Uncommitted)

  • 定义:一个事务可以读取其他事务尚未提交的更改。
  • 问题
    • 存在脏读问题。
    • 不可重复读和幻读问题仍然存在。
  • 场景
    • 事务 A 修改某记录,将余额从 500 改为 300,但未提交。
    • 事务 B 读取该记录时,余额显示为 300。
    • 如果事务 A 回滚,事务 B 看到的数据就是错误的。

优缺点
优点是并发性能高,缺点是数据不可靠。适用于对事务一致性要求极低的场景。

2. 读已提交(Read Committed)

  • 定义:一个事务只能读取到其他事务已提交的数据。
  • 问题
    • 解决了脏读问题。
    • 不可重复读和幻读问题仍然存在。
  • 场景
    • 事务 A 修改记录,将余额从 500 改为 300,但未提交,事务 B 无法看到此更改。
    • 事务 A 提交后,事务 B 再读取该记录,看到余额为 300。

优缺点
数据一致性较高,适用于大多数应用场景。Oracle 数据库默认使用此级别。

3. 可重复读(Repeatable Read)

  • 定义:在一个事务中多次读取相同数据时,结果始终一致,即使其他事务修改了数据。
  • 问题
    • 解决了脏读和不可重复读问题。
    • 但幻读问题仍然存在。
  • 场景
    • 事务 A 查询某记录,第一次读取余额为 500。
    • 事务 B 修改该记录的余额为 300 并提交。
    • 在事务 A 中再次读取余额,结果仍为 500,保持一致。

优缺点
通过 MVCC 技术解决不可重复读问题,InnoDB 默认使用此级别。

4. 可序列化(Serializable)

  • 定义:通过强制事务按顺序执行,确保完全隔离。
  • 问题
    • 解决了脏读、不可重复读和幻读问题。
    • 并发性能最低。
  • 场景
    • 事务 A 查询工资大于 5000 的员工数。
    • 事务 B 插入一名工资为 6000 的新员工,必须等待事务 A 提交后才能执行。

优缺点
完全隔离,数据一致性最强,但性能开销大,适合高要求的金融场景。

3. 隔离级别对并发问题的解决情况

隔离级别脏读不可重复读幻读
读未提交(RU)
读已提交(RC)×
可重复读(RR)××
可序列化(S)×××

4. MySQL 隔离级别的实现细节

MySQL 的 InnoDB 存储引擎通过以下机制实现隔离级别:

  1. 锁机制

    • 行级锁:对单行记录进行加锁,减少锁冲突,提高并发性能。
    • 间隙锁(Gap Lock):锁定索引范围,避免幻读问题。
  2. MVCC(多版本并发控制)

    • 在可重复读隔离级别下,使用 MVCC 技术为每个事务提供“时间点快照”,避免读取到其他事务的修改。

第三部分:事务隔离级别的性能影响、实际使用场景及实现方式

        在选择事务隔离级别时,我们需要综合考虑数据一致性和系统性能,并了解每种隔离级别的具体实现原理。下面逐步展开分析:

1. 隔离级别的性能影响

        事务隔离级别从低到高,对性能的影响逐渐增大:

  1. 读未提交(Read Uncommitted)

    • 性能最高,因为不需要对数据加锁或者版本控制。
    • 缺点是数据一致性最低,可能会读到未提交的临时数据,适合对数据准确性要求极低的场景(如临时报表统计)。
  2. 读已提交(Read Committed)

    • 性能较高,仅使用短时间锁定,读取已提交数据,减少了脏读问题。
    • 缺点是仍可能存在不可重复读和幻读问题,适用于 OLTP(在线事务处理)系统,例如大部分电商订单场景。
  3. 可重复读(Repeatable Read)

    • 性能中等,通过 MVCC 技术避免不可重复读问题。
    • 会引入间隙锁(Gap Lock)防止幻读,这可能导致更多锁争用,适合对数据一致性要求较高的业务场景,例如库存管理。
  4. 可序列化(Serializable)

    • 性能最低,因为事务是串行执行的,需要加锁或控制访问范围,可能会导致大量事务等待。
    • 适合高一致性需求的场景,例如金融转账、证券交易。

2. 实际使用场景建议

  • 读未提交(RU)
    适用于日志分析、临时数据汇总等场景,这些场景对数据的最终一致性要求不高。

  • 读已提交(RC)
    推荐作为通用隔离级别,适用于电商、社交平台等对性能和一致性均衡要求的场景。

  • 可重复读(RR)
    适用于需要保证多个查询结果一致的场景,例如库存查询或长时间事务操作。

  • 可序列化(S)
    使用场景较少,适用于需要严格一致性且并发量低的场景,如银行核心账户系统。

3. 四种隔离级别的实现方式

        在 MySQL 中,隔离级别通过 锁机制MVCC(多版本并发控制) 实现:

1. 读未提交(Read Uncommitted)的实现

  • 实现机制
    • 不加锁,直接读取最新数据,即使这些数据未提交。
    • 数据的可见性完全依赖于修改的事务状态,因此可能导致脏读。

2. 读已提交(Read Committed)的实现

  • 实现机制
    • 读取数据时,事务只访问已经提交的版本。
    • 使用短时锁(读锁)来保证读取的数据已经提交,避免脏读。
    • MVCC 机制:为每个事务维护一个快照,读取时仅访问在事务启动时已经提交的数据版本。

3. 可重复读(Repeatable Read)的实现

  • 实现机制
    • 使用 MVCC 技术,保证在一个事务内读取到的所有数据版本一致。
    • 为了避免幻读问题,InnoDB 在范围查询时引入 间隙锁(Gap Lock),锁定数据范围,阻止其他事务插入新数据。
    • 例子
      • 如果查询“工资 > 5000 的记录”,事务会锁住满足条件的记录以及索引范围,其他事务不能在范围内插入新记录。

4. 可序列化(Serializable)的实现

  • 实现机制
    • 使用读写锁(Shared/Exclusive Lock)强制事务串行化。
    • 事务读取数据时,会加共享锁(S 锁),其他事务无法修改;事务写入数据时,会加排他锁(X 锁),阻止其他事务读取或修改。
    • 执行范围查询时,锁定整个查询范围,完全避免幻读。
http://www.lryc.cn/news/495854.html

相关文章:

  • 异常--C++
  • SeggisV1.0 遥感影像分割软件【源代码】讲解
  • 锁-读写锁-Swift
  • Kafka如何保证消息可靠?
  • 5.10【机器学习】
  • [白月黑羽]关于仿写股票数据软件题目的解答
  • 详解LZ4文件解压缩问题
  • vue项目中单独文件的js不存在this.$store?.state怎么办
  • Github提交Pull Request教程 Git基础扫盲(零基础易懂)
  • Java函数式编程【二】【Stream的装饰】【中间操作】【map映射器】【摊平映射器flatMap】
  • 树莓派明明安装了opencv和numpy,却找不到
  • numpy.float8不存在;Python中,实现16位浮点数
  • Redis集群配置 (不使用docker 部署)
  • HTML5系列(7)-- Web Storage 实战指南
  • 【在Linux世界中追寻伟大的One Piece】读者写者问题与读写锁
  • 用到动态库的程序运行过程
  • 类型转换与IO流:C++世界的变形与交互之道
  • Pytorch使用手册- TorchVision目标检测微调Tutorial的使用指南(专题十二)
  • 人工智能机器学习算法分类全解析
  • Linux 35.6 + JetPack v5.1.4@DeepStream安装
  • 图数据库 | 11、图数据库架构设计——高性能图存储架构(下)
  • 【HTTP】HTTP协议
  • 大数据新视界 -- Hive 基于 MapReduce 的执行原理(上)(23 / 30)
  • SpringBoot源码解析(六):打印Banner
  • 【计算机网络】实验6:IPV4地址的构造超网及IP数据报
  • easy excel 生成excel 文件
  • Ajax:回忆与节点
  • Python+OpenCV系列:Python和OpenCV的结合和发展
  • Ubuntu20.04 由源码编译安装opencv3.2 OpenCV
  • A058-基于Spring Boot的餐饮管理系统的设计与实现