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

【MySQL】事务(二)

事务

  • 一、隔离级别
    • 1、读未提交(Read Uncommitted)
      • (1)介绍
      • (2)示例
    • 2、读已提交(Read Committed)
      • (1)介绍
      • (2)示例
    • 3、可重复读(Repeatable Read)
      • (1)介绍
      • (2)示例
    • 4、串行化(Serializable)
      • (1)介绍
    • 5、四种隔离级别的问题与锁的关系
  • 二、数据库并发的场景
    • 1、读-读并发场景
    • 2、读-写并发场景
    • 3、写-写并发场景
  • 三、MVCC
    • 1、基本概念
    • 2、工作原理
    • 3、在MySQL中的实现
  • 四、RR 与 RC的本质区别

本文是文章【MySQL】事务(一)的续篇

一、隔离级别

1、读未提交(Read Uncommitted)

(1)介绍

  • 提供了最少的并发控制,允许事务读取其他事务未提交的数据。通常不推荐使用,因为它破坏了事务的隔离性,可能导致数据不一致。
  • 可能导致脏读(Dirty Read),即读取到可能无效或会被回滚的数据。

(2)示例

  • 终端A
set global transaction isolation level read uncommitted;
--重启客户端

在这里插入图片描述

begin;
insert into account values (3, 'snowdragon', 98765.4);
  • 终端B

在这里插入图片描述

2、读已提交(Read Committed)

(1)介绍

  • 事务只能读取其他事务已经提交的数据。避免了脏读问题,确保了数据的一致性。适用于对数据一致性有一定要求,但可以容忍不可重复读的场景,如一些在线查询系统。
  • 可能出现不可重复读(Non-Repeatable Read),即在同一事务内,多次读取同一数据可能会得到不同的结果,因为其他事务可能在此期间对数据进行了修改并提交。

(2)示例

  • 终端A
set global transaction isolation level read committed;
--重启客户端
select * from account;

在这里插入图片描述

begin;
update account set blance=432.1 where id=1;
  • 终端B
    在这里插入图片描述
  • 终端A
commit;
  • 终端B

在这里插入图片描述

3、可重复读(Repeatable Read)

(1)介绍

  • 在同一事务内多次读取同一数据集合的结果是一致的。避免了不可重复读问题,确保了数据的一致性。MySQL的InnoDB存储引擎通过多版本并发控制(MVCC)机制来实现这一级别。
  • 在某些情况下可能出现幻读(Phantom Read),即一个事务在读取某些行后,另一个事务插入新行并提交,然后第一个事务再次读取同样的范围时,看到了这些新的“幻影”行。不过,InnoDB通过间隙锁(Gap Lock)或Next-Key Lock解决了幻读问题。
  • 可重复读为MySQL的默认隔离级别,适用于大多数需要保证数据一致性的场景,如财务系统。

(2)示例

  • 终端A
set global transaction isolation level repeatable read;
--重启客户端

在这里插入图片描述

begin;
update account set blance=98432.1 where id=1;
  • 终端B

在这里插入图片描述

  • 终端A
commit;
  • 终端B

在这里插入图片描述

4、串行化(Serializable)

(1)介绍

  • 事务之间完全隔离,一个事务必须等待另一个事务完成后才能执行。适用于对数据一致性要求极高,且可以接受低并发性能的场景,如银行核心系统。
  • 串行化提供了最强的并发控制,避免了脏读、不可重复读和幻读问题。但性能开销极大,因为事务之间的等待和锁竞争会显著增加,导致并发性能极低。

5、四种隔离级别的问题与锁的关系

在这里插入图片描述

二、数据库并发的场景

1、读-读并发场景

  • 多个事务同时读取数据,由于没有数据被修改,因此不存在并发问题。数据库系统不需要进行额外的并发控制措施。
  • 每个事务读取的数据都是相同的,不会影响其他事务的读取结果。
  • 如果数据库中的数据量非常大,多个事务同时读取大量数据可能会导致系统资源的过度消耗,影响系统性能。

2、读-写并发场景

  • 当一个事务读取数据而另一个事务同时进行写入时,可能会引发线程安全问题,导致事务隔离性问题。常见问题有脏读、幻读和不可重复读。

3、写-写并发场景

  • 多个事务同时对同一数据进行写入操作。
  • 常见问题有更新丢失,即当两个事务同时更新同一数据,其中一个事务的更新可能会被另一个事务覆盖;数据冲突,即多个事务对同一数据进行写入操作,可能会导致数据不一致。
  • 解决策略,数据库系统通常采用加锁机制(如共享锁、排他锁)来确保事务的一致性和完整性。
  • 共享锁允许多个事务同时读取同一数据,但不允许任何事务进行写入操作。排他锁只允许一个事务对数据进行写入操作,其他事务既不能读取也不能写入。

三、MVCC

1、基本概念

  • 多版本并发控制(Multiversion Concurrency Control,简称MVCC)允许多个事务同时对数据库进行读写操作,而不会相互阻塞,从而提高了数据库的并发性能。
  • 在MVCC中,每个事务看到的数据版本是不同的,这取决于事务的开始时间。当一个事务对数据进行修改时,它不会直接覆盖原始数据,而是创建一个新的版本。其他事务可以继续访问旧版本的数据,而不会受到正在进行的修改的影响。
  • MVCC提高了数据库的并发性能,允许多个事务同时进行读写操作而不相互阻塞;实现了事务的隔离性,通过维护数据的多个版本来避免脏读、不可重复读和幻读等问题;减少了锁的竞争,降低了系统的开销。
  • MVCC只适用于特定的隔离级别,如可重复读(REPEATABLE READ)和提交读(READ COMMITTED)。其他隔离级别(如未提交读和可串行化)与MVCC不兼容。
  • 在某些情况下,MVCC可能会导致额外的存储开销,因为需要保存数据的多个版本。当事务数量非常多时,版本链可能会变得非常复杂,导致性能下降。

2、工作原理

  • 版本链:在MySQL中,每个数据行都有一个隐藏的列,称为事务ID(Transaction ID,简称TID)。当一个事务对数据行进行修改时,它会将当前的事务ID记录在数据行中。同时,MySQL会为这个修改创建一个新的版本,并将旧版本的数据链接起来,形成一个版本链。
  • 事务的可见性判断:当一个事务查询数据时,MySQL会根据事务的开始时间和数据行的版本链来判断哪些版本的数据对该事务是可见的。具体的判断规则通常基于事务ID的比较。
  • 并发控制:MVCC通过版本链和事务的可见性判断来实现并发控制。多个事务可以同时对数据库进行读写操作,而不会相互阻塞。具体来说,当一个事务对数据进行修改时,它只会创建一个新的版本,而不会影响其他事务对旧版本数据的访问。同时,当一个事务查询数据时,它只会看到符合自己可见性规则的版本,而不会看到其他事务正在进行的修改。

3、在MySQL中的实现

  • 在MySQL中,InnoDB存储引擎通过undo log和Read View两种技术实现了MVCC。
  • undo log:InnoDB将行记录快照保存在了undo log里。回滚指针将数据行的所有快照记录都通过链表的结构串联起来,每个快照的记录都保存了当时的db_trx_id,即那个时间点操作这个数据的事务ID。这样,如果我们想要找历史快照,就可以通过遍历回滚指针(db_roll_ptr)的方式进行查找。
  • Read View:读视图是在使用MVCC机制进行快照读操作时产生的事务视图。这个视图是对当前数据库中所有活跃的、尚未提交的事务ID列表进行拍照的。有了undo log就可以读取到记录的历史版本,而Read View则解决了行的可见性问题。

四、RR 与 RC的本质区别

  • 在RR(可重复读)级别下的某个事务对某条记录的第一次快照读时,会创建一个快照及Read View,将当前系统活跃的其他事务记录起来。此后在调用快照读的时候,使用的是同一个Read View,所以该事务对之后其他事务的修改不可见。而早于Read View创建的事务所做的修改均可见。
  • 在RC(读已提交)级别下的事务中,每次快照读都会新生成一个快照和Read View,这是在RC级别下的事务中可以看到别的事务提交的更新的原因。所以,RC才会有不可重复读问题。

本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
本文只是在学习过程中所做的总结,不会涉及过深的概念
创作不易,如果觉得博主写得不错,请点赞、收藏加关注支持一下💕💕💕


http://www.kler.cn/a/510410.html

相关文章:

  • [JavaScript] 运算符详解
  • 如何在不暴露MinIO地址的情况下,用Spring Boot与KKFileView实现文件预览
  • QT笔记- Qt6.8.1 Android编程 添加AndroidManifest.xml文件以支持修改权限
  • 二叉树总结(hot100)
  • CSS:语法、样式表、选择器
  • 小白:react antd 搭建框架关于 RangePicker DatePicker 时间组件使用记录 2
  • 二叉树OJ题:挑战与突破
  • springboot自动配置原理(高低版本比较)spring.factories文件的作用
  • RISC-V精简指令集
  • 雷电9最新版安装Magisk+LSPosd(新手速通)
  • 基于SSM的家庭记账本小程序设计与实现(LW+源码+讲解)
  • Git实用指南:忽略文件、命令别名、版本控制、撤销修改与标签管理
  • 国产编辑器EverEdit - 文字对齐
  • Golang学习笔记_27——单例模式
  • S4 HANA凭证更改记录
  • Xilinx FPGA :开发使用及 Tips 总结
  • K8S-Pod资源清单的编写,资源的增删改查,镜像的下载策略
  • 基于无线传感器网络的森林防火设备远程监控系统(论文+源码)
  • 根据进程id查看服务使用的垃圾收集器
  • 论文阅读:CosAE Learnable Fourier Series for Image Restoration
  • 大数据面试——引入
  • 【NextJS】PostgreSQL 遇上 Prisma ORM
  • 单链表的删除实战
  • NEC纪实 :2024全国机器人大赛 Robocon 常州工学院团队首战国三
  • QT笔记- Qt6.8.1 Android编程 添加AndroidManifest.xml文件以支持修改权限
  • VB.net实战(VSTO):解决WPS Ribbon图标灰色背景