数据库脏读、不可重复读、幻象读

2024-02-13 09:50

本文主要是介绍数据库脏读、不可重复读、幻象读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

整体介绍

数据库的事务隔离级别(TRANSACTION ISOLATION LEVEL)是一个数据库上很基本的一个概念。为什么会有事务隔离级别,SQL Server上实现了哪些事务隔离级别?事务隔离级别的前提是一个多用户、多进程、多线程的并发系统,在这个系统中为了保证数据的一致性和完整性,我们引入了事务隔离级别这个概念,对一个单用户、单线程的应用来说则不存在这个问题。

一、解释

1.脏读:一个事务读到另外一个事务还没有提交的数据,我们称之为脏读。

2.不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,我们称之为不可重复读。

3.幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中)。

二、事务的隔离级别

从级别低到高依次为:

READ UNCOMMITTED 幻像读、不可重复读和脏读都允许。

READ COMMITTED 允许幻像读、不可重复读,但不允许脏读。

REPEATABLE READ 允许幻像读,但不允许不可重复读和脏读。InnoDB默认级别

SERIALIZABLE 幻像读、不可重复读和脏读都不允许。

但是InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read)。

ORACLE数据库支持 READ COMMITTED 和 SERIALIZABLE ,不支持 READ UNCOMMITTED 和 REPEATABLE READ 。


示例demo

首先,我们来看一下高并发的系统中会存在哪些问题,为了便于理解我们以张三在招商银行的账号和存款为例。

一、准备工作:

1. 创建一个银行账号Table(只是为了说明问题,不考虑表的设计范式)
CREATE TABLE dbo.BankAccount
(
BankAccountId CHAR(16) NOT NULL, -- 银行账号
UserName NVARCHAR(32) NOT NULL, -- 用户
Balance DECIMAL(19, 2) NOT NULL, -- 余额
LastUpdate SMALLDATETIME NOT NULL
)
GO

2. 准备数据
INSERT INTO dbo.BankAccount
VALUES ('9555500100071120', N'张三', 10000.00, GETDATE()) -- 北京分行账号
INSERT INTO dbo.BankAccount
VALUES ('9555507551227787', N'张三', 20000.00, GETDATE()) -- 深圳分行账号
GO

3. 查看数据
SELECT * FROM dbo.BankAccount

二、应用场景

假设张三在招商银行开设了两个账号,一个是招商银行北京分行,一个是招商银行深圳分行,两个账号的余额分别是10,000和20,000。

1. 张三在网上做了一笔交易,交易额100,买方小王通过银行汇款100到张三的北京分行的账号(见下面左图),柜台操作人员向张三账号存入100(事务一),然后系统些操作日志(假设需要10秒,WAITFOR DELAY '00:00:10')正在此时张三在ATM查了一下账号上余额(事务二),发现已经是10100,于是回去准备发货,但是事务一在写操作日志时超时,这是事务回滚,存款交易被取消,钱退给了小王,这样张三查到的账号余额事实上是事务一还没有提交的数据,导致张三错误的认为已经收到交易款项。
dirtyread1 dirtyread2
一个事务读到另外一个事务还没有提交的数据,我们称之为脏读。
解决方法:把事务隔离级别调整到READ COMMITTED,即把右上图中的SET TRAN ISOLATION LEVEL READ UNCOMMITTED更改成下图中的SET TRAN ISOLATION LEVEL READ COMMITTED。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果,因为此时事务以已经把自己的更改ROLLBACK了,所以事务二可以返回正确的结果。

dirtyread3

2. 张三先后两次查询某一账号的余额,在两次查询期间,小王完成了银行转账,导致两次的查询结果不同。

unrepeatable1unrepeatable2
一个事务先后读取同一条记录,但两次读取的数据不同,我们称之为不可重复读。
解决方法:把事务隔离级别调整到REPEATABLE READ。在下图中使用SET TRAN ISOLATION LEVEL REPEATABLE READ。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果。

unrepeatable3

3. 张三妻子先后两次查询张三招商银行所有账号的总余额,而在此期间张三在广州招商银行分行成功开设了一个账号,并存入5000,导致张三妻子两次查询的总余额不同,在此期间张三原有两个账号的余额均未发生改变。
serializable1 serializable2
一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中。)。
解决方法:把事务隔离级别调整到SERIALIZABLE。在下图中使用SET TRAN ISOLATION LEVEL SERIALIZABLE。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果。

serializable3

三、总结

事务隔离级别是通过数据库的锁机制来控制的,在不同的应用场景需要应用不同的事务隔离级别,SQL Server默认的事务隔离级别是READ COMMITTED,默认的隔离级别,已经可以满足我们大部分应用的需求。


本文为加工整合说明,

http://www.cnblogs.com/Sun_Blue_Sky/articles/2139996.html

http://www.cnblogs.com/qkhh/p/4736594.html

http://blog.csdn.net/memray/article/details/8051893

这篇关于数据库脏读、不可重复读、幻象读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/705187

相关文章

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Oracle数据库如何切换登录用户(system和sys)

《Oracle数据库如何切换登录用户(system和sys)》文章介绍了如何使用SQL*Plus工具登录Oracle数据库的system用户,包括打开登录入口、输入用户名和口令、以及切换到sys用户的... 目录打开登录入口登录system用户总结打开登录入口win+R打开运行对话框,输php入:sqlp

Redis 多规则限流和防重复提交方案实现小结

《Redis多规则限流和防重复提交方案实现小结》本文主要介绍了Redis多规则限流和防重复提交方案实现小结,包括使用String结构和Zset结构来记录用户IP的访问次数,具有一定的参考价值,感兴趣... 目录一:使用 String 结构记录固定时间段内某用户 IP 访问某接口的次数二:使用 Zset 进行

数据库使用之union、union all、各种join的用法区别解析

《数据库使用之union、unionall、各种join的用法区别解析》:本文主要介绍SQL中的Union和UnionAll的区别,包括去重与否以及使用时的注意事项,还详细解释了Join关键字,... 目录一、Union 和Union All1、区别:2、注意点:3、具体举例二、Join关键字的区别&php

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed