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

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

相关文章

解决IDEA报错:编码GBK的不可映射字符问题

《解决IDEA报错:编码GBK的不可映射字符问题》:本文主要介绍解决IDEA报错:编码GBK的不可映射字符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录IDEA报错:编码GBK的不可映射字符终端软件问题描述原因分析解决方案方法1:将命令改为方法2:右下jav

MySQL重复数据处理的七种高效方法

《MySQL重复数据处理的七种高效方法》你是不是也曾遇到过这样的烦恼:明明系统测试时一切正常,上线后却频频出现重复数据,大批量导数据时,总有那么几条不听话的记录导致整个事务莫名回滚,今天,我就跟大家分... 目录1. 重复数据插入问题分析1.1 问题本质1.2 常见场景图2. 基础解决方案:使用异常捕获3.

数据库面试必备之MySQL中的乐观锁与悲观锁

《数据库面试必备之MySQL中的乐观锁与悲观锁》:本文主要介绍数据库面试必备之MySQL中乐观锁与悲观锁的相关资料,乐观锁适用于读多写少的场景,通过版本号检查避免冲突,而悲观锁适用于写多读少且对数... 目录一、引言二、乐观锁(一)原理(二)应用场景(三)示例代码三、悲观锁(一)原理(二)应用场景(三)示例

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Win11安装PostgreSQL数据库的两种方式详细步骤

《Win11安装PostgreSQL数据库的两种方式详细步骤》PostgreSQL是备受业界青睐的关系型数据库,尤其是在地理空间和移动领域,:本文主要介绍Win11安装PostgreSQL数据库的... 目录一、exe文件安装 (推荐)下载安装包1. 选择操作系统2. 跳转到EDB(PostgreSQL 的

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处