MySQL 事务并发执行时的一致性问题

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL 事务并发执行时的一致性问题

MySQL 是一个客户端/服务器架构的软件。对于同一个服务器来说,可以有多个客户端与之连接。每个客户端与服务器建立连接后,就形成了一个会话。每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分。服务器可以同时处理来自多个客户端的多个事务。

在某个事务访问某个数据时,如要求其他试图访问相同数据的事务进行限制 , 让它们进行排队。当该事务提交之后,其他事务才能继续访问这个数据。这样可以让并发执行的事务的执行结果与串行执行的结果一样,我们把这种多个事务的执行方式称为可串行化执行。

## 事务并发执行时遇到的一致性问题

### 脏写(Dirty Write)

如果一个事务修改了另一个未提交事务修改过的数据,就意味着发生了脏写现象。我们可以把脏写现象简称为 PO 。假设现在事务 T1 和 T2 并发执行 , 它们都要访问数据项 x (这里可以将数据项 x 当作一条记录的某个字段).那么 PO 对应的操作执行序列如下所示 :

```

P0:w1[x]...w2[x]...((c1 or a1) and (c2 or a2) in any order)

```

其中 w1[x]表示事务 T1 修改了数据项 x 的值。w2[x] 表示事务 T2 修改了数据项 x 的值,C1 表示事务 T1 的提交 (Commit),a1 表示事务 T1 的中止 (Abort),c2 表示事务 T2 的提交,a2 表示事务 T2 的中止,...表示其他的一些操作。从 P0 的操作执行序列中可以看出,事务 T2 修改了未提交事务 T1 修改过的数据, 所以发生了脏写现象。

脏写现象也可能破坏原子性和持久性。比方说有 x 和 y 这两个数据项,它们初始的值都是 0。 两个并发执行的事务 T1 和 T2 有下面的操作执行序列:

```

w1[x=2]w2[x=3]w2[y=3]c2a1

```

现在的问题是 T1 中止时, 需要将它对数据库所做的修改回滚到该事务开启时的样子,也就是将数据项 x 的值修改为 0 . 但是此时 T2 已经修改过数据项 x 并且提交了,如果要将 T1 回滚的话,相当于要对 T2 对数据库所做的修改进行部分回滚(部分回滚是指只回滚对 x 做的修改,而不回滚对 y 做的修改),这就影响到了事务的原子性。如果要将 T2 对数据库所做的修改全部回滚的话 , 那么明明 T2 己经提交了,它对数据库所做的修改应该具有持久性,怎么能让一个未提交的事务将 T2 的持久性破坏掉呢?

### 脏读(Dirty Read)

如果一个事务读到了另一个未提交事务修改过的数据,就意味着发生了脏读现象,我们可以把脏读现象简称为 P1。 假设现在事务 T1 和 T2 并发执行,它们都要访问数据项 x。 那么 P1 对应的操作执行序列如下所示 :

```sql

P1:w1[x]...r2[x]...(( c1 or a1) and (c2 or a2) in any order)

```

脏读现象也可能引发一致性问题。比方说事务 T1 和 T2 中要访问 x 和 y 这两个数据项,我们的一致性需求就是让 x 的值和 y 的值始终相同,x 和 y 的初始值都是 0. 现在并发执行事务 T1 和 T2,它们的操作执行序列如下所示 :

```sql

w1[x=1]r2[x=1]r2[y=0]c2w1[y=1]c1

```

很显然 T2 是一个只读事务,依次读取 x 和 y 的值。可是由于 T2 读取的数据项 x 是未提交事务 T1 修改过的值,所以导致最后读取 x 的值为 1,Y 的值为 0 。虽然最终数据库状态还是一致的(最终变为了 x=1,y=1),但是 T2 却得到了一个不一致的状态。数据库的不一致状态是不应该暴露给用户的。P1 代表的事务的操作执行序列其实是一种脏读的广义解释,针对脏读还有一种严格解释。为了与广义解释进行区分,我们把脏读的严格解释称为 A1。 A1 对应的操作执行序列如下所示 :

```sql

A1:w1[x]...r2[x]...(a1 and c2 in any order)

```

也就是 T1 先修改了数据项 x 的值,然后 T2 又读取了未提交事务 T1 针对数据项 x 修改后的值,之后 T1 中止而 T2 提交。这就意味着 T2 读到了一个根本不存在的值,这也是脏读的严格解释。很显然脏读的广义解释是覆盖严格解释包含的范围的。

### 不可重复读(Non-Repeatable Read)

如果一个事务修改了另一个未提交事务读取的数据 ,就意味着发生了不可重复读现象,或者叫模糊读 ( Fuuzzy Read) 现象。我们可以把不可重复读现象简称为 P2。假设现在事务 T1 和  T2 并发执行,它们都要访问数据项 x。那么 P2 对应的操作执行序列如下所示:

```sql

P2: r1[x]...w2[x]...((c1 or a1) and (c2 or a2) in any order)  

```

不可重复读现象也可能引发一致性问题。比方说事务 T1 和 T2 中要访问 x 和 y 这两个数据项,我们的一致性需求就是让 x 的值和 y 的值始终相同,x 和 y 的初始值都是 0。现在并发执行事务 T1 和 T2。它们的操作执行序列如下所示:

```sql

r1[x=O]w2[x=1]w2[y=1]c2r1[y=1]c1  

```

很显然 Tl 是一个只读事务,依次读取 x 和 y 的值.可是由于 T1 在读取数据项 x 后,T2 接着修改了数据项 x 和 y 的值,并且提交,之后 T1 再读取数据项 y。这个过程中虽未发生脏写和脏读(因为 T1 读取 y 的值时,T2 已经提交),但最终 T1 得到的 x 的值为 0, Y 的值为 1。很显然这是一个不一致的状态,这种不一致的状态是不应该暴露给用户的。

P2 代表的事务的操作执行序列其实是一种不可重复读的广义解释,针对不可重复读还有一种严格解释。为了与广义解释进行区分,我们把不可重复读的严格解释称为 A2。A2 对应的操作执行序列如下所示:

```sql

A2:r1[x]...w2[x]...c2...r1[x]...c1

```

也就是 T1 先读取了数据项 x 的值,然后 T2 又修改了未提交事务 T1 读取的数据项 x 的值,之后 T2 提交,然后 T1 再次读取数据项 x 的值时会得到与第一次读取时不同的值。这也是不可重复读的严格解释。很显然不可重复读的广义解释是覆盖严格解释包含的范围的。

### 幻读(Phantom)

如果一个事务先根据某些搜索条件查询出一些记录,在该事务未提交时,另一个事务写入一些了符合那些搜索条件的记录(这里的写入可以指 INSERT、 DELETE、UPDATE 操作),就意味着发生了幻读现象。我们可以把幻读现象简称为 P3。假设现在事务 T1 和 T2 并发执行, 那么 P3 对应的操作执行序列如下所示 :

```sql

P3:r1[P]...w2[y in P]...((c1 or a1) and (c2 or a2) any order)

```

其中 r1[P] 表示 T1 读取一些符合搜索条件 P 的记录,w2[y in P]表示 T2 写入一些符合搜索条件 P 的记录。

幻读现象也可能引发一致性问题。比方说现在符合搜索条件 P 的记录条数有 3 条。我们有一个数据项 z 专门表示符合搜索条件 P 的记录条数,它的初始值当然也是 3。我们的一致性需求就是

让 z 表示符合搜索条件 P 的记录数.现在并发执行事务 T1 和 T2,它们的操作执行序列如下所示:

```sql

r1[P]w2[insert y to P]r2[z=3]w2[z=4]c2r1[z=4]c1

```

T1 先读取符合搜索条件 P 的记录,然后 T2 插入了一条符合搜索条件 P 的记录,并且更

新数据项 z 的值为 4。然后 T2 提交,之后 T1 再读取数据项 z。z 的值变为了 4,这与 T1 之前

实际读取出的符合搜索条件 P 的记录条数不合,不符合一致性需求。

P3 代表的事务的操作执行序列其实是一种幻读的广义解释,针对幻读还有一种严格解释。

为了与广义解释进行区分,我们把幻读的严格解释称为 A3, A3 对应的操作执行序列如下所示:

```sql

A3:r1[p]...w2[y in P]...c2...r1[p]...c1

```

也就是 T1 先读取符合搜索条件 P 的记录,然后 T2 写入了符合搜索条件 P 的记录。之后  T1 再读取符合搜索条件 P 的记录时,会发现两次读取的记录是不一样的。

#### MySQL 中的幻读

上面关于脏写、脏读、不可重复读、幻读的讨论均属于理论范畴,不涉及具体数据库。对于 MySQL 来说,幻读强调的就是一个事务在按照某个相同的搜索条件多次读取记录时,在后读取时读到了之前没有读到的记录。这个「后读取到的之前没有读到的记录」可以是由别的事务执行 INSERT 语句插入的,也可能是别的事务执行了更新记录键值的 UPDATE 语句而插入的。这些之前读取时不存在的记录也可以被称为幻影记录。假设 T1 先根据搜索条件 P 读取了一些记录,接着 T2 删除了一些符合搜索条件 P 的记录后提交,如果 T1 再读取符合相同搜索条件的记录时获得了不同的结果集,我们就可以把这种现象认为是结果集中的每一条记录分别发生了不可重复读现象。

## 参考资料

- 《A critique of ANSI SQL isolation levels》

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
20天前
|
存储 关系型数据库 MySQL
MySQL MVCC全面解读:掌握并发控制的核心机制
【10月更文挑战第15天】 在数据库管理系统中,MySQL的InnoDB存储引擎采用了一种称为MVCC(Multi-Version Concurrency Control,多版本并发控制)的技术来处理事务的并发访问。MVCC不仅提高了数据库的并发性能,还保证了事务的隔离性。本文将深入探讨MySQL中的MVCC机制,为你在面试中遇到的相关问题提供全面的解答。
58 2
|
29天前
|
缓存 关系型数据库 MySQL
MySQL并发支撑底层Buffer Pool机制详解
【10月更文挑战第18天】在数据库系统中,磁盘IO操作是性能瓶颈之一。为了提高数据访问速度,减少磁盘IO,MySQL引入了缓存机制。其中,Buffer Pool是InnoDB存储引擎中用于缓存磁盘上的数据页和索引页的内存区域。通过缓存频繁访问的数据和索引,Buffer Pool能够显著提高数据库的读写性能。
78 2
|
26天前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
97 43
|
17天前
|
缓存 NoSQL 关系型数据库
mysql和缓存一致性问题
本文介绍了五种常见的MySQL与Redis数据同步方法:1. 双写一致性,2. 延迟双删策略,3. 订阅发布模式(使用消息队列),4. 基于事件的缓存更新,5. 缓存预热。每种方法的实现步骤、优缺点均有详细说明。
|
20天前
|
存储 关系型数据库 MySQL
MySQL MVCC深度解析:掌握并发控制的艺术
【10月更文挑战第23天】 在数据库领域,MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种重要的并发控制机制,它允许多个事务并发执行而不产生冲突。MySQL作为广泛使用的数据库系统,其InnoDB存储引擎就采用了MVCC来处理事务。本文将深入探讨MySQL中的MVCC机制,帮助你在面试中自信应对相关问题。
61 3
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1630 14
|
27天前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
49 1
|
1月前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
26天前
|
监控 关系型数据库 MySQL
MySQL并发控制与管理
【10月更文挑战第17天】MySQL并发控制与管理
24 0
|
26天前
|
存储 监控 关系型数据库
MySQL并发控制与管理:优化数据库性能的关键
【10月更文挑战第17天】MySQL并发控制与管理:优化数据库性能的关键
110 0