五分钟后,你将真正理解MySQL事务隔离级别!

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 在SQL标准中定义了四种隔离级别,每一种级别都定义了一个事务所做的修改,在另外一个事务内和事务间,哪些是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

什么是事务?

事务是一组原子性的SQL操作,所有操作必须全部成功完成,如果其中有任何一个操作因为崩溃或其他原因无法执行,那么所有的操作都不会被执行。也就是说,事务内的操作,要么全部执行成功,要么全部执行失败。

事务的结束有两种,当事务中的所有操作全部成功执行时,事务提交。如果其中一个操作失败,将发生回滚操作,撤消之前到事务开始时的所有操作。

事务的特性

一个运行良好的事务处理系统,还需要具备四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持续性(Durability)。这四个特性简称为ACID特性。

原子性(Atomicity)

一个事务必须被视为一个不可分割的最小逻辑工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。对于一个事务来说,不可能只执行其中的一部分操作,而不执行其中的另外一部分操作,这就是事务的原子性。

一致性(Consistency)

事务执行的结果必须是从一个一致性的状态转换到另外一个一致性的状态。当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果事务因为崩溃或其他原因尚未完成,被迫中断最终事务没有提交,那么事务中所做的修改也不会保存到数据库中。

隔离性(Isolation)

通常来说,一个事务的执行不能其它事务干扰。也就是说,一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。后面我们将要讲解隔离级别(Isolation Level)的时候,会发现为什么我们要说“通常来说”是隔离的。

持续性(Durability)

事务一旦提交,它对数据库中的数据的修改就应该是永久性的。此时即使系统崩溃,修改的数据也不会丢失。不过,实际上持久性也分很多不同的级别,有些持久性策略能够提供非常强的安全保障,而有些则未必。

事务隔离级别

在SQL标准中定义了四种隔离级别,每一种级别都定义了一个事务所做的修改,在另外一个事务内和事务间,哪些是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

未提交读(Read Uncommitted)

未提交读级别中,事务中的修改即使没有提交,对其他事务也是可见的。读取到了事务没有提交的数据,就被成为脏读(Dirty Read)。事务没有提交的数据是很“脏”的,被读取到会引起很多问题。从性能角度上看,未提交读级别不会比其他级别好很多,但缺乏其他级别的好处,所以在实际应用中很少被用到。

为加上深对未提交读级别的理解,让我们看一个脏读的例子,首先设置事务隔离级别为未提交读

mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

再检验一下事务隔离级别:

mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)

左右分别为两个用户,左边是用户A,右边是用户B,时间线从上至下:

#用户A:查询user表,有一条OneMoreStudy的记录        ↓
mysql> select * from user;                        ↓
+----+--------------+                            ↓
| id | name         |                            ↓
+----+--------------+                            ↓
|  1 | OneMoreStudy |                            ↓
+----+--------------+                            ↓
1 row in set (0.00 sec)                            ↓
                                                ↓
                                                ↓            #用户B:开始事务
                                                ↓            mysql> start transaction;
                                                ↓            Query OK, 0 rows affected (0.00 sec)
                                                ↓            
                                                ↓            #用户B:更新user表的一条记录
                                                ↓            mysql> update user set name = 'OMS' where id = 1;
                                                ↓            Query OK, 1 row affected (0.01 sec)
                                                ↓            Rows matched: 1  Changed: 1  Warnings: 0
                                                ↓
#用户A:查询user表,有一条OMS的记录,脏读            ↓
mysql> select * from user;                        ↓
+----+------+                                    ↓
| id | name |                                    ↓
+----+------+                                    ↓
|  1 | OMS  |                                    ↓
+----+------+                                    ↓
1 row in set (0.00 sec)                            ↓
                                                ↓
                                                ↓            #用户B:提交事务
                                                ↓            mysql> commit;
                                                ↓            Query OK, 0 rows affected (0.00 sec)

提交读(Read Committed)

提交读级别中,一个事务开始时,只能查询到其他的事务已经提交的修改。也就是说,一个事务从开始到提交之前,任何的修改对其他的事务都是不可见的。提交读级别基本满足了事务的隔离性。

不过,在同一事务中两次查询之间,有其他事务的修改被提交,那么两次查询到结果可能不相同,这就是不可重复读

为了更好的理解不可重复读,让我们看一个例子,首先设置事务隔离级别为提交读

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

再检验一下事务隔离级别:

mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set, 1 warning (0.00 sec)

左右分别为两个用户,左边是用户A,右边是用户B,时间线从上至下:

#用户A:开始事务
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

#用户A:查询user表,有一条OneMoreStudy的记录
mysql> select * from user;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | OneMoreStudy |
+----+--------------+
1 row in set (0.00 sec)

                                                        #用户B:更新user表的一条记录
                                                        mysql> update user set name = 'OMS' where id = 1;
                                                        Query OK, 1 row affected (0.00 sec)
                                                        Rows matched: 1  Changed: 1  Warnings: 0

#用户A:查询user表,有一条OMS的记录,不可重复读
mysql> select * from user;
+----+------+
| id | name |
+----+------+
|  1 | OMS  |
+----+------+
1 row in set (0.00 sec)

#用户A:提交事务
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

可重复读(Repeatable Read)

可重复读级别中,保证了在同一个事务中多次读取同样记录的结果是一致的。即使多次读取之间有其他事务对其结果做了修改,同一个事务中多次读取的结果也是一致的。可重复读级别也是MySQL的默认事务隔离级别。

不过,当一个事务在读过某个范围内的记录时,其他事务又在这个范围内插入了新的记录,当之前的事务再一次读取这个范围的记录时,不会读取到新插入的那条记录,这被称为幻读

为了更好的理解幻读,让我们看一个例子,首先把事务隔离级别设置为可重复读

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

再检验一下事务隔离级别:

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

左右分别为两个用户,左边是用户A,右边是用户B,时间线从上至下:

#用户A:开始事务
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

#用户A:查询user表,有一条记录
mysql> select * from user;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | OneMoreStudy |
+----+--------------+
1 row in set (0.00 sec)

                                                            #用户B:插入一条数据
                                                            mysql> insert into user (name) value ('OneMoreStudy');
                                                            Query OK, 1 row affected (0.01 sec)

#用户A:查询user表,还是一条记录,幻读
mysql> select * from user;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | OneMoreStudy |
+----+--------------+
1 row in set (0.00 sec)

#用户A:提交事务
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

#用户A:查询user表,两条记录
mysql> select * from user;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | OneMoreStudy |
|  2 | OneMoreStudy |
+----+--------------+
2 rows in set (0.00 sec)

可串行化(Serializable)

可串行化级别中,强制事务串行执行,是最高的隔离级别。在这个级别中,虽然避免了上面提到的幻读,但是会在读取的每一行上加锁,可能导致大量的超时和锁竞争问题,所以在实际应用中很少被用到。除非,非常需要确保数据一致性并且不要求高并发,可以采用可串行化级别。

总结

本文首先简单介绍了事务及其ACID特性,然后着重讲解了事务的四种隔离级别:

  1. 未提交读:事务中的修改即使没有提交,对其他事务也是可见的。
  2. 提交读:事务开始时,只能查询到其他的事务已经提交的修改。
  3. 可重复读:保证在同一个事务中多次读取同样记录的结果是一致的。
  4. 可串行化:强制事务串行执行。
隔离级别 脏读 不可重复读 幻读
未提交读 可能 可能 可能
提交读 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化 不可能 不可能 不可能


万猫学社

微信扫描二维码,关注万猫学社

获得更多Java技术干货。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
|
2月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
124 43
|
26天前
|
关系型数据库 MySQL
mysql事务特性
原子性:一个事务内的操作统一成功或失败 一致性:事务前后的数据总量不变 隔离性:事务与事务之间相互不影响 持久性:事务一旦提交发生的改变不可逆
|
24天前
|
关系型数据库 MySQL 数据库
MySQL事务隔离级别及默认隔离级别的设置
在数据库系统中,事务隔离级别是一个关键的概念,它决定了事务在并发执行时如何相互隔离。MySQL提供了四种事务隔离级别,每种级别都解决了不同的并发问题。本文将详细介绍这些隔离级别以及MySQL的默认隔离级别。
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1698 14
|
3月前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
689 18
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
2月前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
2月前
|
存储 关系型数据库 MySQL
RR隔离级别在MySQL中的实现与幻读问题探讨
【10月更文挑战第3天】在数据库管理系统中,事务隔离级别是确保数据一致性和并发性能的关键要素。MySQL作为广泛使用的关系型数据库管理系统,支持多种事务隔离级别,其中可重复读(Repeatable Read,简称RR)是其默认隔离级别。本文将深入探讨RR隔离级别在MySQL中的实现原理,以及RR隔离级别下幻读问题的产生与解决方案。
120 2
|
3月前
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
169 4
MySQL基础:事务
|
3月前
|
关系型数据库 MySQL 数据库
深入理解MySQL数据库隔离级别
深入理解MySQL数据库隔离级别
142 1

推荐镜像

更多
下一篇
DataWorks