首页 > 其他分享 >脏读、幻读、不可重复读图解

脏读、幻读、不可重复读图解

时间:2023-09-24 12:00:28浏览次数:37  
标签:事务 隔离 幻读 -- 脏读 图解 级别 READ 读取

mysql事务隔离级别

MySQL提供了不同的隔离级别,包括:

  1. READ UNCOMMITTED(读取未提交):最低的隔离级别,不提供任何数据一致性保证,可能会出现不可重复读问题。

  2. READ COMMITTED(读取已提交):默认隔离级别,保证了一个事务不会读取到其他未提交事务的数据修改,但仍可能出现不可重复读问题。

  3. REPEATABLE READ(可重复读):保证在一个事务内多次读取相同数据时结果是一致的,解决了不可重复读问题。但仍可能出现幻读问题,即在一个事务内多次查询时,结果集的行数可能发生变化。

  4. SERIALIZABLE(可串行化):提供最高的隔离级别,保证了所有事务的串行执行,从而避免了不可重复读和幻读问题。但性能开销较高,不适用于所有场景。

你可以通过设置SET TRANSACTION ISOLATION LEVEL语句来更改事务的隔离级别

 

脏读

 

概念:脏读(Dirty Read)是数据库事务隔离级别中的一个问题,它发生在一个事务中读取了另一个未提交的事务中的数据。这可能会导致不一致的结果,因为读取的数据可能在后续被回滚或修改。

可能的后果:读可能导致数据的不一致性。因为读取的数据可能会在未来被回滚或修改,所以一个事务可能会基于不准确或不稳定的数据做出决策,从而引发问题。

 

在MySQL中,默认的事务隔离级别是可重复读(REPEATABLE READ),这意味着默认情况下不会发生脏读。

 

解决脏读:为了解决脏读问题,数据库管理系统通常使用锁定机制或隔离级别来控制并发访问。

 

脏读演示

1. 创建表、数据、查看隔离级别

CREATE TABLE accounts (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    balance DECIMAL(10, 2)
);

INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000.00);

-- 查看默认隔离级别
SHOW VARIABLES LIKE 'transaction_isolation';

  

 

默认mysql默认隔离级别就是可重复读(REPEATABLE-READ)

2. 事务1

事务1:将事务隔离级别改为读未提交,然后开启事务(事务未提交)、指向update操作。在该事务内此数据以及被修改为900.00(之前是1000.00)

-- 设置事务隔离级别为READ UNCOMMITTED
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- 开启事务,但未提交
START TRANSACTION;

-- 修改账户余额
UPDATE accounts SET balance = 900.00 WHERE id = 1;

-- 在Session A中查看账户余额
SELECT * FROM accounts WHERE id = 1;

  

事务1修改事务隔离级别只是临时修改,在此会话内生效

 

3. 事务2:发生了脏读

事务2设置事务隔离级别为读未提交,然后查询事务1修改的数据,发现读取到事务1修改未提交的数据,此时发生了脏读。

-- 设置事务隔离级别为READ UNCOMMITTED
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 在Session B中读取账户余额
SELECT * FROM accounts WHERE id = 1;

  

 事务2修改事务隔离级别只是临时修改,在此会话内生效

3. 事务3

 

 

事务3使用了mysql默认的事务隔离级别(可重复读),此隔离级别永远不会发生脏读,因此读取的数据是1000.00

最佳实践

1. 使用合适的事务隔离级别

MySQL支持多种事务隔离级别,包括READ UNCOMMITTED(最低级别,允许脏读)、READ COMMITTED、REPEATABLE READ和SERIALIZABLE(最高级别)。

要解决脏读问题,通常应该使用至少READ COMMITTED级别的隔离级别。默认情况下,MySQL使用REPEATABLE READ级别。

-- 设置事务隔离级别为READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

  

2. 使用事务

确保你的操作包含在事务中,这样可以确保一组相关的操作要么全部成功,要么全部失败。这有助于避免脏读问题。

-- 开始一个事务
START TRANSACTION;

-- 执行数据库操作
-- ...

-- 提交事务
COMMIT;

  

3. 使用锁定

如果需要,可以使用锁定来防止其他事务读取或修改数据,直到你完成操作。

-- 通过FOR UPDATE锁定行
SELECT * FROM table_name WHERE condition FOR UPDATE;

-- 通过LOCK TABLES锁定表
LOCK TABLES table_name WRITE;
-- 执行操作
UNLOCK TABLES;

  

4. 避免长时间持有锁

长时间持有锁可能会导致性能问题和死锁。因此,在事务中只有必要的时间内持有锁,并在不需要锁时释放它们。

 

示例

-- 设置事务隔离级别为READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 开始一个事务
START TRANSACTION;

-- 查询数据
SELECT * FROM orders WHERE status = 'processing';

-- 进行一些更新操作
UPDATE orders SET status = 'completed' WHERE order_id = 123;

-- 提交事务
COMMIT;

  

 不可重复读

 1. 概念

MySQL的不可重复读(Non-Repeatable Read)是数据库隔离级别中的一种情况,它描述了在一个事务内,两次读取相同数据可能会得到不同的结果。这种现象可以在多个并发事务同时操作数据库时发生,其中一个事务修改了某一行的数据,而另一个事务在事务开始和结束之间读取了同一行的数据。这个问题通常在较低的隔离级别下(如Read Committed)更容易发生,因为它允许在一个事务未提交之前其他事务可以读取已修改的数据。

因为mysql默认隔离级别是可重复读,因此此问题默认不会发生。

2. 不可重复读演示

1. 事务1

-- 设置事务隔离级别为READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 开启事务
START TRANSACTION;

SELECT * FROM accounts WHERE id = 1

  

balance此时的值为1000.00

 

2. 事务2

-- 设置事务隔离级别为READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 开启事务
START TRANSACTION;

-- 更新账户余额
UPDATE accounts SET balance = 150.00 WHERE id = 1;

-- 提交事务
COMMIT;

  

把数据更新为150.00

3. 事务1

事务1,再次执行 SELECT * FROM accounts WHERE id = 1 命令,发现查询的结果不是1000.00,而是事务2更新后的值150.00.这样就导致同一个事务,两次读取的数据不一致即不可重复读问题。

 

 

如果事务隔离级别是可重复读,即使事务2把数据更新并提交了事务。事务1两次读取的数据也是一样的即2次读取的都是1000.00。

 

幻读

 

 

概念

幻读指的是在同一事务中,当事务在读取某个范围的数据行时,另一个事务在该范围内插入了新的数据行,导致第一个事务看到了一些它之前不存在的数据行,就像出现了幻觉一样,因此得名“幻读”。

 

幻读演示示例

事务1

事务1:设置事务隔离级别是读已提交,并开启事务查看accouts表数据,此时表数据只有2条

-- 设置事务隔离级别为READ COMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
-- 第1次读取,在事务2执行插入操作之前
SELECT * FROM accounts

  

 

事务2

事务2执行插入操作

INSERT INTO accounts (id, name, balance) VALUES (3, 'Allen3', 888888.88);

  

 

3. 事务1

继续执行查询表数据操作,发现此时的数据从2条,变成了3条即发生了幻读。

SELECT * FROM accounts 

  

 

最佳实践

使用更高的隔离级别比如可重复度、串行化。或者锁表(不建议)

 

标签:事务,隔离,幻读,--,脏读,图解,级别,READ,读取
From: https://www.cnblogs.com/allenxx/p/17725738.html

相关文章

  • 手摸手图解 CodeWhisperer 的安装使用
    CodeWhisperer是亚⻢逊出品的一款基于机器学习的通用代码生成器,可实时提供代码建议。亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术,观点,和项目,并将中国优秀开发者......
  • java内存分配(堆,栈,方法区,常量池)图解
    大家都知道,java程序是运行在jvm(java虚拟机)上的,因此Java的内存分配是在JVM中进行的。那么在程序内存分配上面,大致分为:本地方法栈、程序计数器、虚拟机栈、java堆、方法区。这五类,本次主要讲解的是虚拟机栈、java堆和方法区中的内容。栈:存放基本数据类型的数据、引用数据类型的变量......
  • java语言基础--对象内存图解
    在JVM内存里面主要分布有以下三个区域:栈:存放基础数据和自定义对象的引用堆:主要存储创建的对象,即new出来的对象。方法区:加载存放class文件(字节码文件)创建一个对象: 通过上图来看,程序是这样执行的:将StudentTest01.class文件加载到方法区将Student.class文件加载到方法区......
  • Linux上Oracle 11g安装步骤图解
    Oracle11g安装准备工作目录Oracle11g安装准备工作Oracle11g下载地址:Oracle11g 联机文档:Oracle11gR2数据库安装硬件配置要求:Linux平台需要的软件包支持:创建Oracle用户修改内核参数修改用户限制修改用户验证选项修改用户配置文件安装目录配置修改用户bashsh......
  • 图解几种常见 Kubernetes Pod 驱逐场景
    图解几种常见KubernetesPod驱逐场景sysdig 奇妙的Linux世界 2023-09-1708:20 发表于重庆 1人听过收录于合集#云原生263个#Kubernetes280个#Docker203个#开源461个公众号关注 「奇妙的Linux世界」设为「星标」,每天带你玩转Linux! KubernetesPod被......
  • 图解 Kubernetes 中应用平滑升级4种方式
    如果你已经使用Kubernetes一段时间了,则可能需要考虑计划定期升级。从Kubernetes1.19开始,每个开源版本都提供一年的补丁。你需要升级到最新的可用次要版本或补丁版本才能获得安全性和错误修复。但是,如何在不停机的情况下升级基础架构的关键部分呢?本文将指导你了解在任何环境中......
  • 二分查找【多种方法+图解】
    (二分查找【多种方法+图解】)前言二分查找其实是一个十分容易理解的方法,在很多人思路里都知道先这个..再那个....,其实二分查找也有许多细节需要去细细分析介绍以及简单思路介绍二分查找是对于一个有序数组进行查找,如果数组无序,可以通过最简单的冒泡排序去排序1找到数组的......
  • 《算法图解》的读书体会
    最近工作有点内耗严重,经常头痛,静下心来读一本书架里的书,好久没有练算法了,程序员算法还是不能丢,在这里分享读书体会。有时候看一本书并不一定是抱着学习的心思去读,那样太累,学习太枯燥了,抱着玩的心态去读,更能让我读下去。如果遇到问题,绕开它,我们不一定要解决问题,逃避问题也是处理问......
  • 图解RAID存储技术:RAID 0、1、5、6、10、50、60
    下午好,我的网工朋友。硬盘设备是计算机中较容易出现故障的元器件之一,也是网工们最经常接触到的设备之一,用途广泛。但是,硬盘不能像CPU、内存、电源甚至主板那样在出现故障后换新的去解决问题,所以经常会需要让你关注“数据冗余”和“异地备份”这两个模块的工作内容。今天这篇文章就......
  • 一图解密《会呼吸的房子》0碳房屋密码
    ......