在 数据库事务的概念和特性 中介绍了 MySQL 事务的四大特性,其中事务的隔离性就是指当多个事务同时运行时,各事务之间相互隔离,不可互相干扰。如果事务没有隔离性,就容易出现脏读、不可重复读和幻读等情况。

为了保证并发时操作数据的正确性,数据库都会有事务隔离级别的概念。

1) 脏读

脏读是指一个事务正在访问数据,并且对数据进行了修改,但是这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

2) 不可重复读

不可重复读是指在一个事务内,多次读取同一个数据但结果不一致。

在这个事务还没有结束时,另外一个事务也访问了该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

3) 幻读

幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

为了解决以上这些问题,标准 SQL 定义了 4 类事务隔离级别,用来指定事务中的哪些数据改变是可见的,哪些数据改变是不可见的。

MySQL 包括的事务隔离级别如下:

读未提交(READ UNCOMITTED)

读提交(READ COMMITTED)

可重复读(REPEATABLE READ)

串行化(SERIALIZABLE)

MySQL 事务隔离级别可能产生的问题如下表所示:

隔离级别脏读不可重复读幻读

READ UNCOMITTED

READ COMMITTED

×

REPEATABLE READ

×

×

SERIALIZABLE

×

×

×

MySQL 的事务的隔离级别由低到高分别为 READ UNCOMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。低级别的隔离级别可以支持更高的并发处理,同时占用的系统资源更少。

下面根据实例来一一阐述它们的概念和联系。

1. 读未提交(READ UNCOMITTED,RU)

顾名思义,读未提交就是可以读到未提交的内容。

如果一个事务读取到了另一个未提交事务修改过的数据,那么这种隔离级别就称之为读未提交。

在该隔离级别下,所有事务都可以看到其它未提交事务的执行结果。因为它的性能与其他隔离级别相比没有高多少,所以一般情况下,该隔离级别在实际应用中很少使用。

例 1 主要演示了在读未提交隔离级别中产生的脏读现象。

示例 1

1) 先在 test_db 数据库中创建 testnum 数据表,并插入数据。SQL 语句和执行结果如下:

mysql> CREATE TABLEtestnum(-> num INT(4));

Query OK,0 rows affected (0.57sec)

mysql> INSERT INTO testnum (num) VALUES(1),(2),(3),(4),(5);

Query OK,5 rows affected (0.09 sec)

2) 下面的语句需要在两个命令行窗口中执行。为了方便理解,我们分别称之为 A 窗口和 B 窗口。

在 A 窗口中修改事务隔离级别,因为 A 窗口和 B 窗口的事务隔离级别需要保持一致,所以我们使用 SET GLOBAL TRANSACTION 修改全局变量。SQL 语句如下:

mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

Query OK,0 rows affected (0.04sec)

mysql> flushprivileges;

Query OK,0 rows affected (0.04 sec)

查询事务隔离级别,SQL 语句和运行结果如下:

mysql> show variables like '%tx_isolation%'\G*************************** 1. row ***************************Variable_name: tx_isolation

Value:READ-UNCOMMITTED

1 row in set, 1 warning (0.00 sec)

结果显示,现在 MySQL 的事务隔离级别为 READ-UNCOMMITTED。

3) 在 A 窗口中开启一个事务,并查询 testnum 数据表,SQL 语句和运行结果如下:

mysql> BEGIN;

Query OK,0 rows affected (0.00sec)

mysql> SELECT * FROMtestnum;+------+

| num |

+------+

| 1 |

| 2 |

| 3 |

| 4 |

| 5 |

+------+

5 rows in set (0.00 sec)

4) 打开 B 窗口,查看当前 MySQL 的事务隔离级别,SQL 语句如下:

mysql> show variables like '%tx_isolation%'\G*************************** 1. row ***************************Variable_name: tx_isolation

Value:READ-UNCOMMITTED

1 row in set, 1 warning (0.00 sec)

确定事务隔离级别是 READ-UNCOMMITTED 后,开启一个事务,并使用 UPDATE 语句更新 testnum 数据表,SQL 语句和运行结果如下:

mysql> BEGIN;

Query OK,0 rows affected (0.00sec)

mysql> UPDATE testnum SET num=num*2 WHERE num=2;

Query OK,1 row affected (0.02sec)

Rows matched:1 Changed: 1 Warnings: 0

5) 现在返回 A 窗口,再次查询 testnum 数据表,SQL 语句和运行结果如下:

mysql> SELECT * FROMtestnum;+------+

| num |

+------+

| 1 |

| 4 |

| 3 |

| 4 |

| 5 |

+------+

5 rows in set (0.02 sec)

由结果可以看出,A 窗口中的事务读取到了B窗口更新后但是没有提交的数据。

6) 下面在 B 窗口中回滚事务,SQL 语句和运行结果如下:

mysql> ROLLBACK;

Query OK,0 rows affected (0.09 sec)

7) 在 A 窗口中查询 testnum 数据表,SQL 语句和运行结果如下:

mysql> SELECT * FROMtestnum;+------+

| num |

+------+

| 1 |

| 2 |

| 3 |

| 4 |

| 5 |

+------+

5 rows in set (0.00 sec)

当 MySQL 的事务隔离级别为 READ UNCOMITTED 时,首先分别在 A 窗口和 B 窗口中开启事务,在 B 窗口中的事务更新但未提交之前, A 窗口中的事务就已经读取到了更新后的数据。但由于 B 窗口中的事务回滚了,所以 A 事务出现了脏读现象。

使用读提交隔离级别可以解决实例中产生的脏读问题。

2. 读提交(READ COMMITTED,RC)

顾名思义,读提交就是只能读到已经提交了的内容。

如果一个事务只能读取到另一个已提交事务修改过的数据,并且其它事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值,那么这种隔离级别就称之为读提交。

该隔离级别满足了隔离的简单定义:一个事务从开始到提交前所做的任何改变都是不可见的,事务只能读取到已经提交的事务所做的改变。

这是大多数数据库系统的默认事务隔离级别(例如 Oracle、SQL Server),但不是 MySQL 默认的。

例 2 演示了在读提交隔离级别中产生的不可重复读问题。

示例 2

1) 使用 SET 语句将 MySQL 事务隔离级别修改为 READ COMMITTED,并查看。SQL 语句和运行结果如下:

mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

Query OK,0 rows affected (0.00sec)

mysql> show variables like '%tx_isolation%'\G*************************** 1. row ***************************Variable_name: tx_isolation

Value:READ-COMMITTED

1 row in set, 1 warning (0.00 sec)

2) 确定当前事务隔离级别为 READ COMMITTED 后,开启一个事务,SQL 语句和运行结果如下:

mysql> BEGIN;

Query OK,0 rows affected (0.00 sec)

3) 在 B 窗口中开启事务,并使用 UPDATE 语句更新 testnum 数据表,SQL 语句和运行结果如下:

mysql> BEGIN;

Query OK,0 rows affected (0.00sec)

mysql> UPDATE testnum SET num=num*2 WHERE num=2;

Query OK,1 row affected (0.07sec)

Rows matched:1 Changed: 1 Warnings: 0

4) 在 A 窗口中查询 testnum 数据表,SQL 语句和运行结果如下:

mysql> SELECT * fromtestnum;+------+

| num |

+------+

| 1 |

| 2 |

| 3 |

| 4 |

| 5 |

+------+

5 rows in set (0.00 sec)

5) 提交 B 窗口中的事务,SQL 语句和运行结果如下:

mysql> COMMIT;

Query OK,0 rows affected (0.07 sec)

6) 在 A 窗口中查询 testnum 数据表,SQL 语句和运行结果如下:

mysql> SELECT * fromtestnum;+------+

| num |

+------+

| 1 |

| 4 |

| 3 |

| 4 |

| 5 |

+------+

5 rows in set (0.00 sec)

当 MySQL 的事务隔离级别为 READ COMMITTED 时,首先分别在 A 窗口和 B 窗口中开启事务,在 B 窗口中的事务更新并提交后,A 窗口中的事务读取到了更新后的数据。在该过程中,A 窗口中的事务必须要等待 B 窗口中的事务提交后才能读取到更新后的数据,这样就解决了脏读问题。而处于 A 窗口中的事务出现了不同的查询结果,即不可重复读现象。

使用可重复读隔离级别可以解决实例中产生的不可重复读问题。

3. 可重复读(REPEATABLE READ,RR)

顾名思义,可重复读是专门针对不可重复读这种情况而制定的隔离级别,可以有效的避免不可重复读。

在一些场景中,一个事务只能读取到另一个已提交事务修改过的数据,但是第一次读过某条记录后,即使其它事务修改了该记录的值并且提交,之后该事务再读该条记录时,读到的仍是第一次读到的值,而不是每次都读到不同的数据。那么这种隔离级别就称之为可重复读。

可重复读是 MySQL 的默认事务隔离级别,它能确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。在该隔离级别下,如果有事务正在读取数据,就不允许有其它事务进行修改操作,这样就解决了可重复读问题。

例 3 演示了在可重复读隔离级别中产生的幻读问题。

示例 3

1) 在 test_db 数据库中创建 testuser 数据表,SQL 语句和执行结果如下:

mysql> CREATE TABLEtestuser(-> id INT (4) PRIMARY KEY,-> name VARCHAR(20));

Query OK,0 rows affected (0.29 sec)

2) 使用 SET 语句修改事务隔离级别,SQL 语句如下:

mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Query OK,0 rows affected (0.00 sec)

3) 在 A 窗口中开启事务,并查询 testuser 数据表,SQL 语句和运行结果如下:

mysql> BEGIN;

Query OK,0 rows affected (0.00sec)

mysql> SELECT * FROM testuser where id=1;

Emptyset (0.04 sec)

4) 在 B 窗口中开启一个事务,并向 testuser 表中插入一条数据,SQL 语句和运行结果如下:

mysql> BEGIN;

Query OK,0 rows affected (0.00sec)

mysql> INSERT INTO testuser VALUES(1,'zhangsan');

Query OK,1 row affected (0.04sec)

mysql> COMMIT;

Query OK,0 rows affected (0.06 sec)

5) 现在返回 A 窗口,向 testnum 数据表中插入数据,SQL 语句和运行结果如下:

mysql> INSERT INTO testuser VALUES(1,'lisi');

ERROR1062 (23000): Duplicate entry '1' for key 'PRIMARY'mysql> SELECT * FROM testuser where id=1;

Emptyset (0.00 sec)

开启事务后A窗口查询表testuser 的时候可以的看到是没有数据, 但是在插入数据的时候却报错, 提示主键重复, 因为B窗口在另一个事务中已经插入了一条数据导致的, 但是A报错后再次查询还是没有数据的, 这就是幻度, 简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。

使用串行化隔离级别可以解决实例中产生的幻读问题。

4. 串行化(SERIALIZABLE)

如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来。那么这种隔离级别就称之为串行化。

SERIALIZABLE 是最高的事务隔离级别,主要通过强制事务排序来解决幻读问题。简单来说,就是在每个读取的数据行上加上共享锁实现,这样就避免了脏读、不可重复读和幻读等问题。但是该事务隔离级别执行效率低下,且性能开销也最大,所以一般情况下不推荐使用。

mysql 126_MySQL教程126-MySQL事务隔离级别相关推荐

  1. mysql四种事务级别_【MySQL 知识】四种事务隔离级别

    摘要:本篇文章主要是为了对MySQL的四种事务隔离级别的介绍.为了保证数据库的正确性与一致性,数据库事务具有原子性(Atomicity).一致性(Consistency).隔离性(Isolation) ...

  2. js hbs mysql_实例分析MySQL下的四种事务隔离级别

    数据库事务有四种隔离级别: 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据. 提交读(Read Committed):只能读取到已经提交的数据, ...

  3. 【Mysql】一篇文章理清事务隔离级别实现原理MVCC

    目录 0.事务隔离级别 1.MVCC 2.版本控制算法 2.1 select 查询数据伪代码 2.2 可见性算法 0.事务隔离级别 我们都知道mysql innodb引擎支持事务,为了兼顾事务并发时之 ...

  4. mysql如何实现4种事务隔离级别

    MySQL 事务隔离级别 MySQL InnoDB事务的隔离级别有四级,默认是"可重复读"(REPEATABLE READ). 未提交读(READ UNCOMMITTED).另一个 ...

  5. Mysql在可重复读事务隔离级别下怎么解决幻读的

    目录 前言 并发事务产生的问题 更新丢失 回滚丢失 覆盖丢失 脏读 不可重复读 幻读 快照读和当前读 幻读验证 快照读如何避免幻读 当前读如何避免幻读 可重复读隔离级别发生幻读情况 小结 前言 Mys ...

  6. MySQL不可读举例_MySQL事务隔离级别与相关示例(脏读、不可重复读、幻读)

    目录 MySQL8中隔离级别的变量跟之前的版本不一样,之前是tx_isolation,MySQL8改成了transaction_isolation.查看当前隔离级别的命令是 mysql> sel ...

  7. mysql四种事务隔离级别

    mysql事务并发问题 ACID什么的就不啰嗦了.mysql多个事务并发的时候,可能会出现如下问题: 1. 更新丢失 即两个事务同时更新某一条数据,后执行的更新操作会覆盖先执行的更新操作,导致先执行的 ...

  8. mysql四种输入_mysql四种事务隔离级别

    mysql事务并发问题 ACID什么的就不啰嗦了.mysql多个事务并发的时候,可能会出现如下问题: 1. 更新丢失 即两个事务同时更新某一条数据,后执行的更新操作会覆盖先执行的更新操作,导致先执行的 ...

  9. mysql mvcc 读写阻塞_mysql面试题MVCC原理事务隔离级别_aiailingfei的博客-CSDN博客

    原文作者:小小一只鸟 原文标题:mysql面试题MVCC原理事务隔离级别 发布时间:2021-01-19 19:43:38 mysql事务隔离级别可重复读面试题 熊大 话说今天漂亮的妹子给我发过一张图 ...

  10. mysql事务隔离级别

    SQL中定义了4中隔离级别,不同的隔离级别对应着事务中做不同的修改,同时在事务内和事务间的可见性也不同.越低的隔离级别越能支持更高的并发,对系统的开销也越低. 四种隔离级别: 1. read unco ...

最新文章

  1. IHttpHandler的学习(0-2)
  2. Oracle 创建及调用存储过程,脚本示例
  3. 完整的JS表单验证封装类
  4. linux终端常用快捷键
  5. linux bash gt,linux之bash的基础特性(一)--gt;命令历史(history命令),命令补全,路径补全...
  6. 带父节点的平衡二叉树_平衡二叉树的左右旋以及双旋转的图文详解
  7. python sqlite3 怎么把字典存入数据库中.
  8. 北京大学Cousera学习笔记--7-计算导论与C语言基础--基本数据类型变量常量
  9. paddle 图标注_SPC控制图应用步骤
  10. java web背景颜色表,更改表行背景颜色
  11. JDK源码阅读之Long
  12. Java 纸牌游戏 牛牛 逻辑代码 实现
  13. 浏览器https证书存在错误怎么办?
  14. 搜狗百度seo推广优化需要注意的三大事项
  15. ldb文件matlab,MongoDB v4.2.2 安装与配置及常规操作
  16. 下载好看的壁纸,这几个网站就够了
  17. 计算机的隐藏功能应用,电脑也有隐藏功能, 你知道吗?
  18. IC技术圈期刊 2021年第2期
  19. 谷歌地图地理翻遍码,谷歌地图地点搜索
  20. 【零基础】极星9.3下单详解

热门文章

  1. Java基础---继承详解--this/supper---方法的重写与重载
  2. 携程apollo系列-个人开发环境搭建
  3. 2018年技术上该怎样努力
  4. spring boot 启动后执行初始化方法
  5. 「云+未来」上海峰会,报名开启
  6. 微信小程序之弹框modal
  7. The 6th Zhejiang Provincial Collegiate Programming Contest-ProblemA:Second-price Auction
  8. Blackfin DSP学习心得与参考资料
  9. 第二次Soring冲刺计划第一天(团队)
  10. ArcGIS10.6 通过ArcMap发布二维数据服务。