MySQL四种隔离级别及对应示例详解

本文通过实例详细解析MySQL的四种隔离级别:未提交读、提交读、可重复读和可串行化,展示了各自可能导致的问题,如脏读、不可重复读和幻读,并探讨了默认隔离级别及其原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面我们了解了MySQL事务和四种隔离级别,以及各个级别会导致的一些问题,不了解的可以戳这里:高性能MySQL学习一(逻辑架构、并发控制、事务、四种隔离级别、多版本并发控制MVCC),今天我们通过例子来直观的感受一下.

首先声明一下,这里安装的是MySQL8,那么我们先来查看一下MySQL的默认隔离级别

mysql> select @@version;		//MySQL版本
+-----------+
| @@version |
+-----------+
| 8.0.17    |
+-----------+
1 row in set (0.00 sec)

mysql> select @@global.transaction_isolation;		//全局隔离级别
mysql> select @@transaction_isolation; 		//当前会话的隔离级别 

mysql> select @@global.transaction_isolation,@@transaction_isolation;
+--------------------------------+-------------------------+
| @@global.transaction_isolation | @@transaction_isolation |
+--------------------------------+-------------------------+
| REPEATABLE-READ                | REPEATABLE-READ         |
+--------------------------------+-------------------------+
1 row in set (0.00 sec)                                                                            

在这里插入图片描述
这里还是把四种隔离级别以及会造成的问题列个表

脏读不可重复读幻读
Read uncommitted
Read committed×
Repeatable read××
Serializable×××

√:可能出现 ×:不会出现

1、未提交读(Read uncommitted)导致的脏读

建立了student表用于本次实验
在这里插入图片描述
打开一个窗口A,修改其默认隔离级别为read uncommitted

mysql> set session transaction isolation level read uncommitted;	//修改会话的隔离级别
Query OK, 0 rows affected (0.00 sec)

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

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
+----+------+------+
2 rows in set (0.00 sec)

另开一个窗口B,进行数据更新

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
+----+------+------+
2 rows in set (0.00 sec)

mysql> update student set sex='F' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from student;		//更新成功
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | F    |
|  2 | lala | M    |
+----+------+------+
2 rows in set (0.00 sec)

回到窗口A,查看,可以看到B中未进行提交的修改,即造成了脏读现象

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | F    |
|  2 | lala | M    |
+----+------+------+
2 rows in set (0.00 sec)

2、提交读(Read committed)导致的不可重复读
打开一个窗口A,修改其默认隔离级别为read committed

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

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

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
+----+------+------+
2 rows in set (0.00 sec)

进入另一个窗口B,进行数据更新,这里插入数据并提交

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into student values(3,'xixi','F');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

回到窗口A,查询得到了不同的结果,在A的两次查询之间,B更新了一条数据,导致事务A执行同样的操作却得到不同的结果,这就是不可重复读

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
|  3 | xixi | F    |
+----+------+------+
3 rows in set (0.00 sec)

在这里插入图片描述
3、可重复读(Repeatable read)导致的幻读
打开一个窗口A,修改其默认隔离级别为repeatable read

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

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

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
|  3 | xixi | F    |
+----+------+------+
3 rows in set (0.00 sec)

进入另一个窗口B,进行数据更新并提交

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
|  3 | xixi | F    |
+----+------+------+
3 rows in set (0.00 sec)

mysql> update student set name='hehe' where id=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from student;		//数据更新成功
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
|  3 | hehe | F    |
+----+------+------+
3 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

回到窗口A,查看,数据并未更新

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
|  3 | xixi | F    |
+----+------+------+
3 rows in set (0.00 sec)

在这里插入图片描述
这里明明事务B进行数据更新并提交了,但事务A查询却并看不到,这就产生了幻读现象

4、可串行化(Serializable)
打开一个窗口A,修改其默认隔离级别为Serializable,开始事务

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

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE            |
+-------------------------+
1 row in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select *  from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | haha | M    |
|  2 | lala | M    |
|  3 | xixi | F    |
+----+------+------+
3 rows in set (0.00 sec)

另起窗口B,开始事务,进行数据更新,但由于A的隔离级别是serializable,完全锁定了字段,于是B只能等待,超时直接报错
在这里插入图片描述
我们让A事务进行提交,然后事务B才能更新成功

mysql> commit;		//A事务提交
Query OK, 0 rows affected (0.00 sec)

A事务提交后,解除锁定,B事务可以进行数据更新,但这种锁定也带来了效率低下的问题,因而MySQL的默认隔离级别是可重复读(Repeatable read)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值