您当前的位置:首页 > 电脑百科 > 数据库 > SQL Server

SQLSERVER 的四个事务隔离级别到底怎么理解?

时间:2023-02-02 14:55:28  来源:今日头条  作者:一线码农聊技术

一:背景

1. 讲故事

在有关SQLSERVER的各种参考资料中,经常会看到如下四种事务隔离级别。

  • READ UNCOMMITTED
  • READ COMMITTED
  • SERIALIZABLE
  • REPEATABLE READ

随之而来的是大量的文字解释,还会附带各种 脏读, 幻读, 不可重复读 常常会把初学者弄得晕头转向,其实事务的本质就是隔离,落地就需要锁机制,理解这四种隔离方式的花式加锁,应该就可以入门了,那如何可视化的观察 锁 过程呢?这里借助 SQL Profile 工具。

二:四种事务隔离方式

1. 测试数据准备

还是用上一篇创建的 post 表,脚本如下:


CREATE TABLE post(id INT IDENTITY,content char(4000))
GO

INSERT INTO dbo.post VALUES('aaa')
INSERT INTO dbo.post VALUES('bbb')
INSERT INTO dbo.post VALUES('ccc');
INSERT INTO dbo.post VALUES('ddd');
INSERT INTO dbo.post VALUES('eee');
INSERT INTO dbo.post VALUES('fff');

有了测试数据之后,我们按照隔离级别 高 -> 低 的顺序来观察吧。

2. SERIALIZABLE 事务

事务串行化 其实很好理解,如果要在 C# 中找对应那就是 ReaderWriterLock,读写事务是完全排斥的,接下来把 SQLSERVER 的隔离级别调整为 SERIALIZABLE。


SET TRAN ISOLATION LEVEL SERIALIZABLE
GO

BEGIN TRAN 
SELECT * FROM dbo.post WHERE id=3
COMMIT

打开 profile,选择 lock:Acquired, lock:Released,SQL:StmtStarting 选项,开启观察。

 

从图中可以清楚的看到,SQLSERVER 直接对 post 附加了 S 锁,在 COMMIT 之后才真正的释放,在 S 锁期间, Insert 和 Update 引发的 X 锁是进不来的,所以就会存在相互阻塞的情况,也许这就是串行化的由来吧。

sqlserver 是一个支持多用户并发的数据库程序,如果锁粒度这么粗,必定给并发带来非常大的负面影响,不过文章开头的那三个指标 脏读, 幻读, 不可重复读 肯定都是不会出现的。

2. REPEATABLE READ 事务

什么叫 可重复读 呢?简而言之就是同一个 select 查询执行二次,不会出现记录修改的情况,在真实场景中两次 select 查询期间,可能会有其他事务修改了记录,如果当前是 REPEATABLE READ 模式,这是被禁止的,接下来的问题是如何落地实现呢?我们来看看 SQLSERVER 是如何做到的,参考sql 如下:


SET TRAN ISOLATION LEVEL REPEATABLE READ
GO

BEGIN TRAN 
SELECT * FROM dbo.post WHERE id=3
COMMIT

 

这个图可能有些朋友看不懂,我稍微解释一下吧,数据库由数据页Page组成,数据页由记录RID 组成,有了这个基础就好理解了, SQLSERVER 会在事务期间把 1:489:0 也就是 id=3 这个记录全程附加 S 锁,直到事务提交才释放 S 锁,在事务期间任何对它修改的 X 锁都无法对其变更,从而实现事务期间的 可重复读 功能,如果大家不明白可以再琢磨琢磨。

这里有一个细节需要大家注意一下,可重复读 的场景下会出现 幻读 的情况,幻读就是两次查询出的结果集可能会不一样,比如第一次是 3 条记录,第二次变成了 5 条记录,为了方便理解我来简单演示一下。

  • 会话1

SET TRAN ISOLATION LEVEL REPEATABLE READ
GO

BEGIN TRAN 
SELECT * FROM dbo.post WHERE id >3
WAITFOR DELAY '00:00:05'
SELECT * FROM dbo.post WHERE id >3
COMMIT

  • 会话2

在会话1 执行的 5s 期间执行 会话2 语句。


BEGIN TRAN 
INSERT INTO dbo.post(content) VALUES ('gggggg')
COMMIT

稍等片刻之后,会发现多了一个 记录7 ,截图如下:

 

3. READ COMMITTED

提交读 是目前 SQLSERVER 默认的隔离级别,它是以不会出现 脏读 为唯一目标,何为脏读,简而言之就是读取到了别的事务未提交的修改数据,这个数据有可能会被其他事务在后续回滚掉,如果真的被其他事务 回滚 了,那你读到了这样的数据就是 错误 的数据,可能会给你的系统带来非常隐蔽的 bug,为了说明这个现象,我们用两个会话来测试一下帮助大家理解。

  • 会话1

在这个会话中,将 id=3 的记录修改成 zzzzz


BEGIN TRAN 
UPDATE dbo.post SET content='zzzzz' WHERE id=3
WAITFOR DELAY '00:00:05'
ROLLBACK

  • 会话2

这个会话中,重复执行sql查询。


BEGIN TRAN 
SELECT * FROM dbo.post WITH(NOLOCK) WHERE id =3   -- 脏读啦
WAITFOR DELAY '00:00:05'
SELECT * FROM dbo.post WITH(NOLOCK) WHERE id =3   -- 正确的数据
COMMIT

 

为了实现脏读这里加了 nolock 关键词,从图中明显的看到,获取的 zzzzz 数据是错误的,在一些和钱打交道的系统中是被严厉禁止的。

有了这些基础再理解 可提交读 可能会容易些,是不是很好奇 SQLSERVER 是如何实现的呢? 参考 sql 如下:


SET TRAN ISOLATION LEVEL READ COMMITTED
GO

BEGIN TRAN 
SELECT * FROM dbo.post  WHERE id =3  
COMMIT

 

从加锁流程看,SQLSERVER 会逐一扫描数据页附加 IS 锁,扫完马上就释放,不像前面那样保持到 COMMIT 之后,如果找到记录所在的 Page 时,会对下面的所有记录附加 S 锁,这个时候 X 锁就进不来了,这就是它的实现原理,大家可以把刚才的 脏读 的sql中的 nolock 去掉试试看,两次读取结果都是一样的。

4. READ UNCOMMITTED

本质上来说 READ UNCOMMITTED 和 nolock 的效果是一样的,会引发脏读现象,主要是因为 READ UNCOMMITTED 根本就不会对表记录使用任何锁,参考sql如下:


SET TRAN ISOLATION LEVEL READ UNCOMMITTED
GO

BEGIN TRAN 
SELECT * FROM dbo.post  WHERE id =3  
COMMIT

接下来观察 sqlprofile 的输出。

 

可以看到 READ UNCOMMITTED 只会对表和堆表结构这种架构附加锁,不会对表中记录附加任何锁,也就会引发 脏读 现象。

三:总结

其实 SQLSERVER 还有带版本的 SNAPSHOT 隔离级别,在真实场景中往往会给 TempDB 造成很大的压力,这里就不介绍了。

相信通过 Profile 观察到的加锁动态过程,会让大家有更深入的理解。



Tags:SQLSERVER   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
SQLServer 数据库 TEMPDB 数据库文件迁移
问题描述TEMP数据库过大,存在于C盘,单机环境下操作比较简单,仅需要重启即可重建tempdb数据库;AlwaysOn群集环境同样,重启服务即可重建本机节点tempdb数据库;但以上操作治标不治本,...【详细内容】
2023-07-26  Search: SQLSERVER  点击:(260)  评论:(0)  加入收藏
SQLSERVER backup 命令总结
一、概述SQLSERVER有两个命令用于创建备份,分别是: BACKUP DATABASE BACKUP LOG这些命令具有可用于创建完整、差异、文件、事务日志备份等的各种选项,以及用于指定备份命令应如...【详细内容】
2023-04-13  Search: SQLSERVER  点击:(179)  评论:(0)  加入收藏
SQLSERVER 的四个事务隔离级别到底怎么理解?
一:背景1. 讲故事在有关SQLSERVER的各种参考资料中,经常会看到如下四种事务隔离级别。 READ UNCOMMITTED READ COMMITTED SERIALIZABLE REPEATABLE READ随之而来的是大量的文...【详细内容】
2023-02-02  Search: SQLSERVER  点击:(204)  评论:(0)  加入收藏
SQLserver 的 Nolock 到底是怎样的无锁
​一:背景1. 讲故事相信绝大部分用 SQLSERVER 作为底层存储的程序员都知道 nolock​ 关键词,即使当时不知道也会在踩过若干阻塞坑​之后果断的加上 nolock,但这玩意有什么注意...【详细内容】
2023-02-02  Search: SQLSERVER  点击:(279)  评论:(0)  加入收藏
SQLSERVER 居然也能调 C# 代码 ?
一:背景1. 讲故事前些天看到一个奇怪的 Function 函数,调用的是 C# 链接库中的一个 UserLogin 方法,参考代码如下:CREATE FUNCTION dbo.clr_UserLogin( @name AS NVARCHAR(1...【详细内容】
2023-01-03  Search: SQLSERVER  点击:(296)  评论:(0)  加入收藏
SQLServer时间戳的误解,与时间没有关系
有很多朋友也都会误认为:时间戳是一个时间字段,每次增加数据时,填入当前的时间值。其实这误导了很多朋友。时间戳仅仅是个一直在递增的标识版本号,与时间没有任何关系。时间戳...【详细内容】
2022-10-18  Search: SQLSERVER  点击:(462)  评论:(0)  加入收藏
Javascript怎样访问Sqlserver数据库
Javascript无法直接访问SqlServer数据库的,但可以使用浏览器的“执行SQL”功能查询数据库,将查询结果保存在浏览器变量中,然后在Javascript代码中引用这些变量即可。在浏览器的...【详细内容】
2022-07-11  Search: SQLSERVER  点击:(994)  评论:(0)  加入收藏
SQLSERVER也能部署在linux环境?SQLServer2019在CENTOS7部署详解
概述我们知道SQL Server是微软公司推出的重要的数据库产品,通常情况下只支持部署在windows平台上。不过令人感到兴奋的是,从SQL Server 2017开始支持 linux系统。此 SQL Serve...【详细内容】
2021-12-17  Search: SQLSERVER  点击:(981)  评论:(0)  加入收藏
SQLServer基础:Apply关键字用法介绍
今天给大家梳理Apply关键字用法,希望对大家能有所帮助!1、概念介绍APPLy关键字是SQLServer版本中开始提供的一个系统关键字。APPLY的功能同联接很类似,APPLY运算分左右两个部...【详细内容】
2021-04-16  Search: SQLSERVER  点击:(502)  评论:(0)  加入收藏
数据库:SQLServer分页查询整理
作为程序员来说,与数据库打交道是十分频繁的分页查询是一个开发者必须掌握的基本知识点,目前整理了下面三种SQLServer分页查询语句的写法,仅供参考。一、Top Not IN 方式(查询...【详细内容】
2020-12-29  Search: SQLSERVER  点击:(600)  评论:(0)  加入收藏
▌简易百科推荐
SQL Server 百万数据查询优化技巧三十则
互联网时代的进程越走越深,使用MySQL的人也越来越多,关于MySQL的数据库优化指南很多,而关于SQL SERVER的T-SQL优化指南看上去比较少,近期有学习SQLSERVER的同学问到SQL SERVER数...【详细内容】
2023-11-28  数据库干货铺  微信公众号  Tags:SQL Server   点击:(343)  评论:(0)  加入收藏
如何解决SQL Server数据库备份过程中检测到的日志损坏问题
译者 | 李睿日志损坏问题通常发生在对事务日志进行备份的时候。其错误是这样描述的:“消息26019,级别16,状态1,第1行BACKUP在数据库日志中检测到损坏。有关详细信息,请查看错误日...【详细内容】
2023-11-08    51CTO  Tags:SQL Server   点击:(297)  评论:(0)  加入收藏
聊聊SQL中的排名问题
今天给大家介绍一下SQL Server排名中经常用到的ROW_NUMBER(),RANK(),DENSE_RANK(),NTILE()这四个好兄弟。 我们先创建一个测试数据表ScoresWITH t AS(SELECT 1 StuID,70 ScoreU...【详细内容】
2023-10-26  SQL数据库开发  微信公众号  Tags:SQL   点击:(177)  评论:(0)  加入收藏
数据库批量插入数据方法
SQL Server 批量插入数据常用方法:一、普通的Insert插入二、拼接BatchInsert插入三、SqlBulkCopy插入 以上3种方法插入数据的速度比较:(ms:毫秒,1000 毫秒 = 1秒)由于电脑硬件情况...【详细内容】
2023-10-17      Tags:数据库   点击:(252)  评论:(0)  加入收藏
如何在 SQL Server 中备份和恢复数据库
在SQL Server中,数据库可以存储在不同的文件和文件组中。如果您的数据库较小(100 MB 或更少),则无需过多担心文件和文件组。但如果您有一个大型数据库(数 GB 或 TB),将数据分离到不...【详细内容】
2023-09-05  祺印说信安  微信公众号  Tags:SQL Server   点击:(272)  评论:(0)  加入收藏
linux上SQL Server 配置管理器的使用
概述我们知道Windows平台上的SQL Server 配置管理器是一个图形工具,用于管理与 SQL Server 关联的服务、配置 SQL Server 使用的网络协议以及管理 SQL Server 客户端计算机的...【详细内容】
2023-08-24    雪竹频道  Tags:SQL Server   点击:(308)  评论:(0)  加入收藏
Linux 上 SQL Server 配置管理器的使用
概述我们知道Windows平台上的SQL Server 配置管理器是一个图形工具,用于管理与 SQL Server 关联的服务、配置 SQL Server 使用的网络协议以及管理 SQL Server 客户端计算机的...【详细内容】
2023-08-21  雪竹聊技术  今日头条  Tags:SQL Server   点击:(124)  评论:(0)  加入收藏
python如何操作SQL Server数据库?
当使用Python与SQL Server进行交互时,可以使用不同的库和模块。以下是25个示例代码,用于演示如何使用Python与SQL Server进行连接、查询、插入、更新和删除等操作:使用pyodbc库...【详细内容】
2023-08-15  运维开发木子李  今日头条  Tags:SQL Server   点击:(297)  评论:(0)  加入收藏
SQL Server关系数据库在Linux系统上安装及配置
SQL Server是由Microsoft开发的关系型数据库管理系统(RDBMS)。它是一种可靠、安全且高性能的数据库解决方案,用于存储、管理和处理大量结构化数据。SQL Server支持标准的SQL查...【详细内容】
2023-08-15  运维开发木子李  今日头条  Tags:SQL Server   点击:(243)  评论:(0)  加入收藏
SQL Server数据库常见操作及命令
创建数据库:CREATE DATABASE database_name;删除数据库:DROP DATABASE database_name;创建表:CREATE TABLE table_name ( column1 datatype, column2 datatype, ...);删除...【详细内容】
2023-08-15  运维开发木子李  今日头条  Tags:SQL Server   点击:(229)  评论:(0)  加入收藏
站内最新
站内热门
站内头条