深入理解MySQL事务的4种隔离级别

作者:一年春又来 时间:2024-01-21 09:52:40 

1 简介

事务的4种隔离级别分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、 可重复读(Repeatable Read)和串行化(Serializable)。

首先,在了解这4种隔离级别前就必须先要了解其前提,也就是事务,本文简单介绍一下关于事务。

之后,我们也要理解这4种隔离级别产生的原因和场景展现以及4种隔离级别是如何解决问题的。

2 什么是数据库事务?

事务由一个有限的数据库操作序列组成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。

例如一个银行转账场景:

A转账B 100元,A的账号扣除100元,B的账号加上100块。假如中间出现任何异常,例如,在A的账号扣100元时,银行瘫痪,B的账号余额没有发生变化。这时候就需要事务来保证将A的钱还回去。

2.1 事务的四大特性(ACID)

  • 原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。

  • 一致性:指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。

  • 隔离性:多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。

  • 持久性:表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。

3 并发事务会导致的问题

  • 脏读:事务 A 读取了事务 B 更新的数据,然后 B 进行回滚操作,那么A读取的数据就是脏数据

  • 不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次夺取同一数据时,结果不一致。

  • 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

💡 不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

3.1 本文会使用到的 SQL 语句

3.1.1 示例表结构

CREATE TABLE `account` (
 `id` int(11) NOT NULL,
 `name` varchar(255) DEFAULT NULL,
 `balance` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `un_name_idx` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.1.2 查询事务的默认隔离级别

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.01 sec)

3.1.3 设置当前会话的事务隔离级别

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

4 事务的4种隔离级别和示例演示

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)又叫读已提交
可重复读(repeatable-read)
串行化(serializable)

4.1 读未提交

事务A:

深入理解MySQL事务的4种隔离级别

事务B:

深入理解MySQL事务的4种隔离级别

💡 读未提交是隔离级别最低的,会造成脏读。

4.2 读已提交

为了避免脏读,数据库有了比读未提交更高的隔离级别,即读已提交

对于提交:当前事务只能读取其它事务已提交的数据,未提交事务的数据读取不到。

事务A:

深入理解MySQL事务的4种隔离级别

事务B:

深入理解MySQL事务的4种隔离级别

由此可以得出结论,隔离级别设置为已提交读(READ COMMITTED)
时,已经不会出现脏读问题了,当前事务只能读取到其他事务提交的数据。但是,站在事务A的角度想想,存在其他问题吗?

提交读的隔离级别会有什么问题呢?

在同一个事务A里,相同的查询sql,读取同一条记录(id=1),读到的结果是不一样的,即不可重复读。所以,隔离级别设置为read committed的时候,还会存在不可重复读的并发问题。

4.3 可重复读

为了避免不可重复读的并发问题,我们将隔离级别设置为可重复读(REPEATABLEE READ),重复一下之前的操作。

事务A:

深入理解MySQL事务的4种隔离级别

事务B:

深入理解MySQL事务的4种隔离级别

到了这一步,可以发现事务隔离级别设置为可重复读,可以解决幻读问题。

那么可重复读真的是否已经解决了幻读问题呢?毕竟还剩个事务隔离级别呢。

RR隔离级别下,手动启动一个事务,进行select操作,他会生成一个快照,可以理解为将当前数据库的数据复制一份,在当前事务中,之后不管进行多少次select查询,都是在模板中去取数据,所以不管数据库中是否对数据进行了改变,都不会影响当前事务数据的读取,从而避免了幻读。这种普通的 select 操作,称为快照读

但是如果在当前事务中使用了下图语句进行当前读:

select * from account for update;

for update是进行当前读的操作,他会重新从数据库去加载当前的最新的数据,每执行一次加载一次,如果在此时,另外一个事务为数据库添加了一个事务,再进行查询,会发现查询的数据与之前相比多了或者少了,这也就是幻读现象。

如果你阅读到这里,去实操一下,会发现和我说的不一样,有一种上当的感觉。

其实不是的,这是因为上述都是在标准的可重复读下的情况,在innodb存储引擎中对可重复读进行了改造,为当前读加上了 Next-key Lock,也就是间隙锁和行锁的统称,行锁防止了别的事务修改或者删除,间隙锁防止了别的事务新增。也就是在进行上面的for update事务中,其他的事务不能对数据进行增删操作,执行会报错或者长时间处于等待状态。

💡 注意:如果A事务如果进行了快照读,然后通过B事务对数据就行增删,然后紧接着A事务进行当前读操作,两次读取数据不一致,不能算作幻读,因为幻读定义是同一个select语句,快照读和当前读的查询语句是不一样的.

小结

  • 数据库的并发问题有:脏读、不可重复读和幻读;

  • 事务隔离级别依次为:读未提交、读已提交、可重复读和串行化;

  • 在标准的RR下并没有彻底解决幻读,但是在Mysql的innodb引擎中彻底解决了;

  • innodb通过 Next-Key lock解决的幻读问题,其实也就是阻塞串行化了;

  • 不能把快照读和当前读在一个事务中进行比较是否出现幻读,两者不是同一个select,不满足幻读的官方定义。

4.4 串行化

略,这部分我懒得放图了,因为结果和上面没啥差别。

文献引用

一文彻底读懂MySQL事务的四大隔离级别 - Jay_huaxiao - 博客园

来源:https://blog.csdn.net/Little_fxc/article/details/124196928

标签:MySQL,事务隔离
0
投稿

猜你喜欢

  • Vue实现登录以及登出详解

    2023-07-02 16:59:51
  • JavaScript设计模式之适配器模式介绍

    2023-08-12 06:36:09
  • python3 中时间戳、时间、日期的转换和加减操作

    2023-12-31 17:41:36
  • SQL Server 2000如何设置会话上下文信息?

    2010-05-18 18:33:00
  • BOF、EOF 属性

    2009-05-11 12:37:00
  • Python装饰器decorator用法实例

    2023-02-06 23:26:43
  • pytorch实现好莱坞明星识别的示例代码

    2022-11-28 14:26:47
  • Runnable.com 在线测试代码片分享网站

    2023-02-04 09:25:54
  • python实现mask矩阵示例(根据列表所给元素)

    2022-04-19 19:37:16
  • Python实现简单的多任务mysql转xml的方法

    2024-01-26 20:11:07
  • python 用户交互输入input的4种用法详解

    2021-09-10 05:19:34
  • 好用的JS图片预加载类

    2007-08-13 13:49:00
  • Django+boostrap 美化admin后台的操作

    2022-02-26 16:16:21
  • pycharm远程调试openstack的图文教程

    2021-10-31 06:37:56
  • 关于团队建设以及网站建设的琐事

    2009-03-19 13:31:00
  • asp如何用通过Web访问OLAP数据?

    2010-06-16 09:52:00
  • vue中使用elementui实现树组件tree右键增删改功能

    2024-05-09 09:53:38
  • python套接字socket通信

    2023-01-26 17:51:03
  • python实现在控制台输入密码不显示的方法

    2023-06-19 22:44:23
  • python格式化字符串实例总结

    2023-09-01 04:36:11
  • asp之家 网络编程 m.aspxhome.com