mysql笔记:21. 演示脏读、不可重复读和幻读现象

文章目录

  • 脏读
    • 1. 设置窗口B中事务的隔离级别
    • 2. 演示脏读
    • 3. 重新设置窗口B中事务的隔离级别
    • 4. 再次验证脏读
  • 不可重复读
    • 1. 演示不可重复读
    • 2. 设置窗口B中事务的隔离级别
    • 3. 再次验证不可重复读
  • 幻读
    • 1. 设置窗口B中事务的隔离级别
    • 2. 演示幻读
    • 3. 重新设置窗口B中事务的隔离级别
    • 4. 再次验证幻读
  • 串行化插入问题
    • 1. 设置窗口B中事务的隔离级别
    • 2. 演示串行化插入问题

在MySQL中,事务有4种隔离级别,分别为READ UNCOMMITTED(读未提交)、READ COMMITTED(读已提交)、REPEATABLE READ(可重复读)和SERIALIZABLE(串行化)。

脏读

READ UNCOMMITTED是事务隔离级别中最低的级别,该级别下的事务可以读取其他事务中未提交的数据,这种读取方式也被称为脏读。
下面以示例数据库employees.departments表为例演示脏读。首先,开启两个终端窗口,分别称为窗口A和窗口B。两个窗口都登录到MySQL数据库并切换到employees库。

1. 设置窗口B中事务的隔离级别

MySQL默认隔离级别是REPEATABLE READ,该级别可以避免脏读。为演示需求,将其隔离级别设置为READ UNCOMMITTED。

mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)# 设置隔离级别
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+------------------+
| Variable_name         | Value            |
+-----------------------+------------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+------------------+
1 row in set (0.00 sec)

2. 演示脏读

在窗口A中开启事务,并更新Sales部门名称为Sales2。

mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales     |
+---------+-----------+
1 row in set (0.01 sec)mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> UPDATE departments SET dept_name='Sales2' WHERE dept_no='d007';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales2    |
+---------+-----------+
1 row in set (0.00 sec)

此时不要提交事务,否则无法演示脏读现象。
切换到窗口B,查询该部门信息。

mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales2    |
+---------+-----------+
1 row in set (0.01 sec)

从结果看,窗口B中可以看到修改后的部门名称,这是由于窗口B的事务隔离级别比较低,因此读取了窗口A中还没有提交的内容,出现了脏读情况。
脏读演示完毕,可以在窗口A中执行ROLLBACK命令回滚事务,让数据恢复初始状态。

3. 重新设置窗口B中事务的隔离级别

为防止脏读的发生,将B中事务的隔离级别设置为READ COMMITTED,该隔离级别可以避免脏读。

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.01 sec)

4. 再次验证脏读

在窗口B中查询部门d007的信息。

mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales     |
+---------+-----------+
1 row in set (0.00 sec)

然后在窗口A中开启事务并修改部门d007的信息。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> UPDATE departments SET dept_name='Sales3' WHERE dept_no='d007';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales3    |
+---------+-----------+
1 row in set (0.00 sec)

修改数据后再次查询d007的部门信息已更新,但数据未提交。此时在窗口B中查询。

mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales     |
+---------+-----------+
1 row in set (0.00 sec)

结果显示窗口B中并没有查询到窗口A中未提交的内容,说明READ COMMITTED隔离级别可以避免脏读。
验证演示完毕,可以在窗口A中执行ROLLBACK命令回滚事务,让数据恢复初始状态。

不可重复读

在MySQL的READ COMMITTED级别下,事务只能读取其他事务已经提交的内容,可以避免脏读现象,但是会出现不可重复读和幻读的情况。
不可重复读是指在事务内重复读取数据,由于多次查询期间,其他事务更新了相关数据,因此出现多次读取结果不一致的现象。

1. 演示不可重复读

在窗口B中设置事务的隔离级别为READ COMMITTED,然后开启事务查询d007的部门信息。

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| 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 departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales     |
+---------+-----------+
1 row in set (0.00 sec)

此时,在窗口A中使用UPDATE语句更新d007的部门信息。

mysql> UPDATE departments SET dept_name='Sales4' WHERE dept_no='d007';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales4    |
+---------+-----------+
1 row in set (0.00 sec)

修改成功后,再次回到窗口B中查询d007的部门信息。

mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales4    |
+---------+-----------+
1 row in set (0.00 sec)

结果显示在一个事务中,相同的查询语句两次查询结果不一致。其实不可重复读并不算错误,但在有些情况下却不符合实际需求。
不可重复读演示完毕,可以在窗口B中执行COMMIT命令提交事务。

2. 设置窗口B中事务的隔离级别

为了防止不可重复读的情况出现,修改窗口B中事务的隔离级别为REPEATABLE READ。

mysql> SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

3. 再次验证不可重复读

在窗口B中开启事务,并查询d007的部门信息。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales4    |
+---------+-----------+
1 row in set (0.00 sec)

在窗口A中使用UPDATE语句更新d007的部门信息:

mysql> UPDATE departments SET dept_name='Sales5' WHERE dept_no='d007';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales5    |
+---------+-----------+
1 row in set (0.00 sec)

然后在窗口B中查询d007的部门信息:

mysql> SELECT * FROM departments WHERE dept_no='d007';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d007    | Sales4    |
+---------+-----------+
1 row in set (0.00 sec)

对比窗口B的两次查询结果,发现窗口B中事务的隔离级别修改为REPEATABLE READ后,查询结果是一致的,并没有出现不同的数据,说明此该级别可以避免不可重复读的情况。
验证演示完毕,可以在窗口B中执行COMMIT命令提交事务。

幻读

幻读又被称为虚读,是指在一个事务内两次查询中的数据条数不一致。幻读和不可重复读类似,都是在两次查询过程中。区别是,幻读是由于其他事务插入记录导致记录数变化而引起的。
理论上,REPEATABLE READ级别可以避免脏读、不可重复读,但会出现幻读。不过MySQL的存储引擎通过多版本并发控制机制解决了该问题,所以当事务隔离级别为REPEATABLE READ时可以避免幻读。

1. 设置窗口B中事务的隔离级别

REPEATABLE READ级别可以避免幻读,所以将事务的隔离级别设置得更低。

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.00 sec)

2. 演示幻读

在窗口B中开启事务,并查询部门名称以字母D开头的信息:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM departments WHERE dept_name LIKE 'D%';
+---------+-------------+
| dept_no | dept_name   |
+---------+-------------+
| d005    | Development |
+---------+-------------+
1 row in set (0.00 sec)

在窗口A中插入新成立的部门Design:

mysql> INSERT INTO departments value('d010', 'Design');
Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM departments WHERE dept_no='d010';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d010    | Design    |
+---------+-----------+
1 row in set (0.01 sec)

切换到窗口B中,再次查询部门名称以字母D开头的信息:

mysql> SELECT * FROM departments WHERE dept_name LIKE 'D%';
+---------+-------------+
| dept_no | dept_name   |
+---------+-------------+
| d010    | Design      |
| d005    | Development |
+---------+-------------+
2 rows in set (0.00 sec)

删除数据和新增数据类似,也会出现幻读现象。

幻读演示完毕,可以在窗口B中执行COMMIT命令提交事务。

3. 重新设置窗口B中事务的隔离级别

为避免幻读现象,将窗口B中事务的隔离级别设置为REPEATABLE READ。

mysql> SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

4. 再次验证幻读

在窗口B中开启事务,并查询部门名称以字母D开头的信息:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM departments WHERE dept_name LIKE 'D%';
+---------+-------------+
| dept_no | dept_name   |
+---------+-------------+
| d010    | Design      |
| d005    | Development |
+---------+-------------+
2 rows in set (0.00 sec)

在窗口A中插入新成立的部门Design2:

mysql> INSERT INTO departments value('d011', 'Design2');
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM departments WHERE dept_no='d011';
+---------+-----------+
| dept_no | dept_name |
+---------+-----------+
| d011    | Design2   |
+---------+-----------+
1 row in set (0.00 sec)

切换到窗口B中,再次查询部门名称以字母D开头的信息:

mysql> SELECT * FROM departments WHERE dept_name LIKE 'D%';
+---------+-------------+
| dept_no | dept_name   |
+---------+-------------+
| d010    | Design      |
| d005    | Development |
+---------+-------------+
2 rows in set (0.00 sec)

对比窗口B中的两次查询结果,发现窗口B设置事务的隔离级别为REPEATABLE READ后,同一个事务的两次查询结果是一致的,并没有读取其他事务新插入的记录。说明REPEATABLE READ可以避免幻读。
验证演示完毕,可以在窗口B中执行COMMIT命令提交事务。

串行化插入问题

事务的隔离级别设置为SERIALIZABLE可以避免脏读、不可重复读和幻读,但也会导致大量的超时和锁竞争,数据库性能极差。

1. 设置窗口B中事务的隔离级别

mysql> SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+--------------+
| Variable_name         | Value        |
+-----------------------+--------------+
| transaction_isolation | SERIALIZABLE |
+-----------------------+--------------+
1 row in set (0.01 sec)

2. 演示串行化插入问题

在窗口B中开启事务,并查询表中数据。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT COUNT(1) FROM departments;
+----------+
| COUNT(1) |
+----------+
|       11 |
+----------+
1 row in set (0.00 sec)

切换到窗口A,并插入新成立的部门Design3:

mysql> INSERT INTO departments value('d012', 'Design3');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

窗口A中执行插入语句后,不会立即执行成功,而是光标闪烁,一直等待。此时提交窗口B中的事务,窗口A中的插入操作会立即执行;否则A中的操作一直等待,直到最后超时提示信息。
默认超时时间是50秒。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/755089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络:TCP篇

计网tcp部分面试总结 tcp报文格式: 序列号:通过SYN传给接收端,当SYN为1,表示请求建立连接,且设置序列号初值,后面没法送一次数据,就累加数据大小,保证包有序。 确认应答号&#x…

Prometheus修改默认数据存储时间

Prometheus的默认数据存储时间可以通过修改启动脚本中的相关参数来调整。具体来说,可以通过修改--storage.tsdb.retention.time参数来改变数据保留的时长。该参数决定了何时删除旧数据,默认为15天。如果需要延长数据保留时间,可以将该参数的值…

【机器学习】函数

sigmoid函数 import matplotlib.pyplot as plt import numpy as npdef sigmoid(x):return 1/(1np.exp(-x))def plot_sigmoid():# param:起点,终点,间距x np.arange(-10, 10, 0.1) #起点,终点,间距y sigmoid(x)plt.plot(x, y)plt…

鸿蒙Harmony应用开发—ArkTS声明式开发(绘制组件:Rect)

矩形绘制组件。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 Rect(value?: {width?: string | number,height?: string | number,radius?: string | number | Array<s…

Sentinel基础使用

1. 概念解释 限流&#xff1a;对并发访问进行限速。限流的一些行为&#xff1a; 1. 拒绝服务&#xff1a;将多余的请求直接拒绝掉2.服务降级&#xff1a;降级甚至关闭后台的某些服务3.特权请求&#xff1a;在多租户或者对用户进行分级时&#xff0c;考虑让特权用户进行访问4.延…

得物java春训营(一面面经)

1.聊项目技术点。 2.java中的threadlocal有了解过吗&#xff1f;使用threadlocal要注意什么呢&#xff1f;&#xff08;平时也没用过&#xff0c;后来复盘的时候才知道有内存泄露的问题&#xff0c;面试官提示到了和线程池共用&#xff0c;最后也没答出来。&#xff09; 3.线程…

代码随想录算法训练营day25 | 216.组合总和III、17.电话号码的字母组合

目录 组合总和III思路解题方法复杂度Code 电话号码的字母组合思路解题方法复杂度Code 总结 组合总和III 链接: 组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列…

论文解析:V3D: Video Diffusion Models are Effective 3DGenerators

摘要&#xff1a; 自动三维生成最近引起了广泛关注。最近的方法大大加快了生成速度&#xff0c;但由于模型容量有限或三维数据&#xff0c;生成的物体通常不够精细。在视频扩散模型最新进展的推动下&#xff0c;我们引入了 V3D&#xff0c;利用预训练视频扩散模型的世界模拟能…

YOLOV5 部署:基于web网页的目标检测(本地、云端均可)

1、前言 YOLOV5推理的代码很复杂,大多数都是要通过命令行传入参数进行推理,不仅麻烦而且小白不便使用。 本章介绍的web推理,仅仅需要十几行代码就能实现本地推理,并且只需要更改单个参数就可以很方便的部署云端,外网也可以随时的使用 之前文章介绍了QT的可视化推理界面,…

Linux初识环境变量

&#x1f30e;环境变量【上】 文章目录&#xff1a; 环境变量 什么是环境变量 关于命令行参数 环境变量       简单了解       为什么需要环境变量       系统中其他环境变量 总结 前言&#xff1a; 环境变量是一种非常重要的概念&#xff0c;它们对于系统的…

TH-FBCQX2防爆气象站

TH-FBCQX2防爆气象站主要适用于易燃易爆、危险性高的场所。以下是其主要的适用领域&#xff1a; 石油与天然气行业&#xff1a;在石油和天然气的生产、储存和运输过程中&#xff0c;防爆气象站可以监测环境中的可燃气体浓度&#xff0c;并根据气象条件预测爆炸风险。同时&…

Machine Learning ---- Gradient Descent

目录 一、The concept of gradient&#xff1a; ① In a univariate function&#xff1a; ②In multivariate functions&#xff1a; 二、Introduction of gradient descent cases&#xff1a; 三、Gradient descent formula and its simple understanding: 四、Formula o…

【sql】深入理解 mysql的EXISTS 语法

相关文章&#xff1a; 【sql】深入理解 mysql的EXISTS 语法 【sql】初识 where EXISTS 1. 使用格式如下&#xff1a; select * from a where exists ( 任何子查询 ) 代码根据颜色分成两段&#xff0c;前面的是主查询&#xff0c;后面红色的是子查询&#xff0c;先主后子&…

手势追踪技术在HTC VIVE中的应用与实现

在虚拟现实(VR)的世界中&#xff0c;手势追踪技术正变得日益重要。它不仅能提升用户的交互体验&#xff0c;使其更加直观和自然&#xff0c;还能在各种应用场景中开辟新的可能性&#xff0c;从游戏和娱乐到专业的培训和设计。作为VR领域的先行者&#xff0c;HTC VIVE提供了一套…

Android弹出通知

发现把Android通知渠道的重要性设置为最高时&#xff0c;当发送通知时&#xff0c;通知能直接弹出来显示&#xff0c;以前一直搞不明白为什么别的app的通知可以弹出来&#xff0c;我的不行&#xff0c;搞了半天原来是这个属性在作怪&#xff0c;示例如下&#xff1a; class Ma…

Java毕业设计 基于springboot vue招聘网站 招聘系统

Java毕业设计 基于springboot vue招聘网站 招聘系统 springboot vue招聘网站 招聘系统 功能介绍 用户&#xff1a;登录 个人信息 简历信息 查看招聘信息 企业&#xff1a;登录 企业信息管理 发布招聘信息 职位招聘信息管理 简历信息管理 管理员&#xff1a;注册 登录 管理员…

后端工程师快速使用axios

文章目录 01.AJAX 概念和 axios 使用模板目标讲解代码解析案例前端后端结果截图 02.URL 查询参数模板目标讲解案例前端后端结果截图 03.常用请求方法和数据提交模板目标讲解案例前端后端结果截图 04.axios 错误处理模板目标讲解案例前端后端结果截图 01.AJAX 概念和 axios 使用…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:ListItem)

用来展示列表具体item&#xff0c;必须配合List来使用。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。该组件的父组件只能是List或者ListItemGroup。 子组件 可以包含单个子组件。 接口 从API…

ASP.NET Core 8.0 WebApi 从零开始学习JWT登录认证

文章目录 前言相关链接Nuget选择知识补充JWT不是加密算法可逆加密和不可逆加密 普通Jwt&#xff08;不推荐&#xff09;项目环境Nuget 最小JWT测试在WebApi中简单使用简单使用运行结果 WebApi 授权&#xff0c;博客太老了&#xff0c;尝试失败 WebApi .net core 8.0 最新版Jwt …

XML和JSON的区别

1、JSON是一种轻量级的数据交换格式 XML是可扩展标记语言。 2、JSON是基于JavaScript语言 XML源自SGML。 3、JSON是一种表示对象的方式 XML是一种标记语言 使用标记结构来表示数据项。 4、JSON不提供对命名空间的任何支持 XML支持名称空间。 5、JSON支持数组 XML不支…