[Database] 脏读、幻读这些都是什么?事务隔离级别又是什么?MySQL数据库的事务隔离级别都有哪些?

article/2025/10/2 23:03:24

文章目录

  • 前言
  • 事务隔离级别
    • 三种数据不一致问题
      • 1. 脏读
      • 2. 不可重复读
      • 3. 幻读
      • 不可重复读 vs 幻读
    • 四种事务隔离级别
      • 1. READ UNCOMMITTED
      • 2. READ COMMITTED
      • 3. REPEATABLE READ
      • 4. SERIALIZABLE
    • 不同事务隔离级别会面临的问题
    • 不同隔离事务级别的使用率排名
  • 实战
    • 查看事务隔离级别
    • 更改事务隔离级别
  • 结语

前言


数据库作为一个服务(进程),不可避免会有被多个用户同时使用的场景。也就是所谓的并发场景,熟悉多线程编程的朋友们也应该都知道高并发下多线程修改共享数据需要做并发控制才能避免我们的共享数据出现错误。这里类比我们的关系型数据库其实也不例外,隔离等级就是关系型数据库提供给我们的并发控制工具。本文将带你了解MySQL提供给我们的事务隔离等级以及不同等级下会面对的不同数据错误问题。

事务隔离级别


事务隔离级别,英:Transaction Isolation Level,有时候会被省略为隔离级别。MySQL的官方文档对其解释如下:

15.7.2.1 Transaction Isolation Levels

大致的意思是:事务隔离是数据库处理的基础之一。隔离(Isolation)在数据库特性缩写的ACID中代表着 I隔离等级则是在多个事务同时进行时,用于平衡性能和事务结果的可靠性、一致性和再现性(reproducibility)的一种设定(Setting)

说白话就是,并发场景下,不同的隔离事务等级有着不同的性能和结果可靠性。严格的隔离等级就意味着性能的损失,但也意味着事务结果更加可靠,反之亦然

三种数据不一致问题

在了解具体不同事务隔离等级之前,我们需要先了解几种数据不一致问题的概念,我们的数据库,通常会面临几种数据不一致问题,分别是:

  1. 脏读
  2. 不可重复度
  3. 幻读

下面我们分别介绍一下这几个概念。

1. 脏读

脏读,英:dirty read。

脏读意味着读到了不可信的数据,比如数据被某个事务更改了,但是明明该事务还没提交,就已经可以被其他事务读到了,只有事务的隔离级别是read uncommitted时才会出现脏读

脏读 Dirty Read

2. 不可重复读

不可重复读,英:non-repeatable read。

不可重复读意味着,在同一个事务里,一个查询被前后两次执行去获取数据,根据数据库ACID的特性,我们认为 同一个事务相同的查询操作去获取数据应该是能得到相同的数据。然而我们一前一后的两个查询却取到了不同的数据(有的数据被其他事务修改并提交因此被读到)。

不可重复度 non-repeatable read

3. 幻读

幻读,英:phantom read。

phantom,有幻觉之意。幻读意味着在同一个事务里,我们执行同一个查询语句两次,一前一后。后一个查询读到了前一个查询里没有的数据(由于其他事务插入了新数据或是更新了数据导致where语句条件通过)。数据的突然出现,就像幻觉一样

幻读 Phantom Read

不可重复读 vs 幻读

如何区分不可重复读和幻读一直是一个问题,因为按照定义幻读其实也是一种不可重复读。毕竟在幻读的场景下同一事务内同一查询操作前后两次请求到的数据确实不一样,也符合不可重复读的前后不一致的定义。

所以如何区分这两个概念呢?笔者这里提供一个思路:

  • 不可重复读:侧重点是前后两次请求到的结果集内数据条数一致,但结果集内的数据并不完全一致的情况。
  • 幻读:侧重点是前后两次请求到的结果集内数据条数不一致

四种事务隔离级别

MySQL的数据存储引擎InnoDB根据SQL:1992 标准的规定,提供了四种事务隔离级别。

4种隔离级别
按隔离严格程度低到高排序 分别是:

  1. READ UNCOMMITTED
  2. READ COMMITTED
  3. REPEATABLE READ(默认隔离级别)
  4. SERIALIZABLE

笔者会在接下来的章节里分别介绍这几种隔离级别。

1. READ UNCOMMITTED

READ UNCOMMITTED,中译:读未提交。

是最不严格的事务隔离级别,速度也最快。如其名,其他事务的未提交(Commit)的修改,也能感知(Read)到。也正是因为如此,使用这种隔离级别会导致前面我们提到的所有三种问题。

2. READ COMMITTED

READ COMMITTED,中译:读提交。

比READ UNCOMMITTED稍微严格一点的事务隔离级别,性能次于READ UNCOMMITTED,和READ UNCOMMITTED相比,一个事务的未提交的修改,不能被其他的事务感知,但一旦提交后,其他能立即感知到这个变化。使用这种隔离级别会导致幻读和不可重复读。

3. REPEATABLE READ

REPEATABLE READ,中译:可重复读。是InnoDB引擎的默认事务隔离级别

比READ COMMITTED更严格一点的事务隔离级别,性能次于READ COMMITTED,和READ COMMITTED相比,其他事务提交的修改,不会影响到当前的事务的多次查询结果。但是对于新数据的插入则会出现幻读(数据条数增加)。

InnoDB为了实现这种隔离级别,用到了MVCC(Multi-Version Concurrency Control / 多版本并发控制)机制。这个机制本文不过多做讨论,有兴趣的读者可以自行搜索关键词MVCC。

4. SERIALIZABLE

SERIALIZABLE,中译:串行化、序列化。是InnoDB引擎最不常用的事务隔离级别。

作为最严格的事务隔离级别,因为额外的控制开销导致这种隔离级别的事务性能最差。但也正因为如此,这个隔离级别的事务不会遇到上述的三种问题中的任意一种。

不同事务隔离级别会面临的问题

不同事务隔离级别的事务会面临不同的问题,为了方便记忆和理解,笔者作了一个表格。

隔离级别脏读不可重复读幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

不同隔离事务级别的使用率排名

在MySQL官方文档里提供了隔离级别的使用率排名。
不同隔离事务级别的使用率排名
从最常用的到最不常用的顺序分别是:

  1. 默认的REPEATABLE READ
  2. READ COMMITTED
  3. READ UNCOMMITTED
  4. SERIALIZABLE

可以看到通常情况下我们不太需要设置默认的隔离事务级别,基本都是够用的。

实战

简单列举几个实战的例子。

查看事务隔离级别

你可以通过在MySQL的命令行客户端执行

show variables like '%tx_isolation%';

select @@tx_isolation;

就可以查询到事务的隔离级别了

查询事务隔离级别

亦或是在你的数据库连接工具里执行也是可以的,如下:

select @@global.tx_isolation;
select @@session.tx_isolation;
select @@tx_isolation;

数据库连接工具

更改事务隔离级别


虽然我们大部分情况使用默认的隔离事务级别即可,但是如果你想使用其他的事务隔离级别。你可以使用SET TRANSACTION命令去实现。

SET TRANSACTION命令

你可以通过下面几种命令去改变SESSION级别的事务隔离级别,全局的GLOBAL通常不推荐修改,没有权限的用户也是会被MySQL拒绝修改的。

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
select @@session.tx_isolation;

变更事务隔离级别

结语


事务之于数据库是非常重要的,而事务隔离级别之于事务也是一样,是非常重要的。理解几种事务隔离级别以及它们面临如脏读、幻读、不可重复读等问题,是更好地理解关系型数据库如何工作的基础。另外文中的大部分知识都在MySQL的官方文档能找到出处,笔者强烈推荐有英语阅读能力的读者们去阅读MySQL官方文档(文中有链接)。

我是虎猫,希望本文对你有所帮助。(=・ω・=)


http://chatgpt.dhexx.cn/article/7qs7FNM4.shtml

相关文章

Mysql-详解脏读、不可重复读、幻读

Mysql的事务隔离级别 Mysql有四种事务隔离级别,这四种隔离级别代表当存在多个事务并发冲突时,可能出现的脏读、不可重复读、幻读的问题。 脏读 大家看一下,我们有两个事务,一个是 Transaction A,一个是 Transaction B…

MySQL的事务,脏读,不可重复读,幻读

一、什么是事务 在MySQL中,事务是一种机制、一个操作序列,是访问和更新数据库的程序执行单元。事务中包含一个或多个数据库操作命令,会把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行&#…

脏读、幻读、不可重复读,傻傻分不清楚

脏读 (针对未提交数据) 脏读又称无效数据读出(读出了脏数据)。一个事务读取另外一个事务还没有提交的数据叫脏读。 例如:事务T1修改了某个表中的一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改…

【MySQL理论】脏读、不可重复读、幻读

文章目录 1. 脏读(dirty read)脏读是指事务读取到其他事务未提交的数据 2. 不可重复读(non-repeatable read)不可重复读是指在同一次事务中前后查询不一致的问题 3. 幻读(phantom read)幻读是一次事务中前后数据量发生变化,用户产生不可预料的问题 4. 不可重复读和幻…

脏读、不可重复读、幻读、丢失更新

根儿上来说,为什么需要事务和锁? 如果所有的操作都是依次进行的,或者说mysql的server是单线程的,就不会有并发问题,也就不需要事务和锁了。然而事实上,是多客户端,多线程的,所有必须…

一文搞懂MySQL脏读,幻读和不可重复读

目录 MySQL 中事务的隔离 1.READ UNCOMMITTED2.READ COMMITTED3.REPEATABLE READ4.SERIALIZABLE前置知识 1.事务相关的常用命令2.MySQL 8 之前查询事务的隔离级别3.MySQL 8 之后查询事务的隔离级别4.查看连接的客户端详情5.查询连接客户端的数量6.设置客户端的事务隔离级别7.新…

脏读、幻读和不可重复读

一、引言 脏读、不可重复读和幻读是数据库中由于并发访问导致的数据读取问题。当多个事务同时进行时可以通过修改数据库事务的隔离级别来处理这三个问题。 二、问题解释 1、脏读(读取未提交的数据) 脏读又称无效数据的读出,是指在数据库访…

一文详解脏读、不可重复读、幻读

MySQL 是支持多事务并发执行的。否则来一个事务处理一个请求,处理一个人请求的时候,其它事务都等着,那估计都没人敢用MySQL作为数据库,因为用户体验太差,估计都要砸键盘了。 既然事务可以并发操作,这里就有一些问题:一…

快速理解脏读、不可重复读和幻读

MySQL的InnoDB引擎是支持事务的,但是并发事务的处理又会带来以下问题: 脏读不可重复读幻读 一、脏读 脏读指事务A读取到了事务B更新了但是未提交的数据,然后事务B由于某种错误发生回滚,那么事务A读取到的就是脏数据。 具体的说…

引用及指针和引用的区别

一.在C语言中,我们要给函数传参,有两种方法。 1.传值 void Swap(int a,int b) {int tmpa;ab;btmp; } int main() {int a10;int b20;Swap(a,b);return 0; }优点:形参不影响实参(保护实参),可读性强。 缺点…

C++ | 指针和引用的区别

01. C——指针和引用的区别 指针是一个存储变量地址的变量,指向内存的一个存储单元。 引用只是一个别名。 int a1; int *p&a;int a1; int &ba;使用sizeof看一个指针的大小是8,而引用则是被引用对象的大小。指针可以被初始化为NULL,…

C++—指针与引用的区别与联系

一、为什么要有引用(C语言没有) ▪ 因为引⽤和值有⼀样的语义,而指针不是 ▪ 不存在空引⽤,必须初始化;保证值不变,保证编译器更加安全 ▪ 加减号、赋值操作符,作⽤在引用上会触发对象的操作符重…

C++指针与引用的区别

指针和引用的区别 ①指针是一个变量,存储一个成员的地址;引用是一个常量(指针常量),相当于一个成员的别名 ②指针声明和定义可以分开;引用声明时必须初始化 int* a;//指针声明 anew int(1);//指针定义 int…

【C++】---指针和引用的区别

指针和引用的区别 两者本质两者区别两者的相同点为什么传引用比传指针更安全两者做返回值效率的比较 两者本质 引用是别名,指针是地址、实体 两者区别 不同点分析1.初始化要求不同引用在创建的同时必须初始化,即引用到一个有效的对象,而指…

【C++】指针和引用的区别及指针传递和引用传递的区别

一、指针和引用的区别: 1.指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;引用和原来的变量实质上是同一个东西,只不过是原变量的一个别名。 2.指针的值在初始化后可变,即指向其…

指针和引用的区别以及引用与指针基础

1引用: 引用(reference)为对象起了另外一个新的名字通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名: int ival 1024;int& refval ival;int& refval2;//报错:引用必须被初始化…

C++中指针和引用的区别(超详细)

指针和引用主要有以下区别: 引用必须被初始化,但是不分配存储空间。指针不声明时初始化,在初始化的时候需要分配存储空间。 引用初始化后不能被改变,指针可以改变所指的对象。 不存在指向空值的引用,但是存在指向空值的…

c++:指针和引用的区别

目录 前言: 1、引用概念上是定义一个变量的别名,而指针是存储一个变量的地址。 2、引用在定义时必须要初始化,但是指针没有要求。 3、引用在初始化时引用一个实体后,就不能再引用其他实体,因为其本质是一个指针常量…

C++中指针和引用的区别

1.指针和引用的定义和性质区别: (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来 的变量实质上是同一个东西,只不过是原变量的一个别…

C++中的指针与引用

写在前面 指针和引用形式上很好区别,但是他们似乎有相同的功能,都能够直接引用对象,对其进行直接的操作。但是什么时候使用指针?什么时候使用引用呢?这两者很容易混淆,在此我详细介绍一下指针和引用,力争将最真实的一…