动手分析SQL Server中的事务中使用的锁

序本文属于基础知识的回顾,在日常技术交流和日常工作中经常发现有些同事了解关于数据库事务的基本知识,会看SQL语句的执行计划,也知道数据库有X锁、U锁和S锁等各种锁,但是对于这些锁在数据库事务执行期间是如何工作?为何这样配合才能完成数据库事务?数据库是如何对于各种资源加锁的?等等这类的问题不太了解,那么对于事务的执行肯定不会有深刻的认识 。
这类知识虽然从网上搜索可以找到很多,但是大多内容重复,并且只注重理论知识而没有实践路径 。就好比池塘中的青莲只可远观而无法靠近仔细观察,犹如雾里看花水中望月,对于其真实原理总是似懂非懂 。
纸上得来终觉浅,绝知此事要躬行,只有亲自动手进行分析才能对这些问题有深入的认识,因此本文计划从数据库的基础知识入手,以详细的实践分析步骤引导认识数据库事务的执行过程,以期读者可以对于事务有更加深刻的理解 。
SQL Server使用的锁及锁对象数据库引擎使用不同的锁模式锁定资源,通过不同锁的组合使用达到不同的数据库事务隔离级别 。
锁模式
编号
效果说明
共享锁
S
共享锁,通常用于不修改数据也不希望数据被修改的场景
更新锁
U
用于可更新的资源,防止这类资源在读取、锁定以及随后可能进行的资源更新时出现死锁
排他锁
X
用于修改数据的操作,例如insert、update和delete,防止对同一个资源进行多重修改
意向锁
 
包括意向共享、意向更新和意向排他三种,用于保护较低级别的锁并提升性能
架构锁
 
用于执行依赖表结构的操作时使用,包括架构修改 (Sch-M) 和架构稳定性 (Sch-S)
大容量更新
BU
在将数据大容量复制到表中且指定了 TABLOCK 提示时使用
键范围
 
当使用可序列化事务隔离级别时保护查询读取的行的范围 。
意向锁又细分为多种类型:
锁模式
编号
效果说明
意向共享
IS
保护针对底层资源的共享锁
意向排他
IX
保护针对底层资源的排他锁是,IS的超集
共享意向排他
SIX
保护针对低层资源请求或获取的意向排他锁以意向共享锁
意向更新
IU
保护针对底层资源的更新锁
共享意向更新
SIU
S锁和IU锁的组合,作为分别获取并同时具备两种锁的组合效果
更新意向排他
UIX
U锁和IX锁的组合,作为分别获取并同时具备两种锁的组合效果
架构锁细分为两种类型:
锁模式
编号
效果说明
架构修改锁
Sch-M
DDL执行期间使用架构修改锁,该锁会阻止对于表的所有访问
架构稳定锁
Sch-S
该锁不会影响S、U以及X锁的执行,但是会阻止DDL的执行
通常开发人员谈到数据库的锁的时候习惯说数据库锁、表锁或者行锁 。这种描述通常是从被锁定资源的角度来谈论,通过检索SQL Server2016的文档发现数据库上锁定更多的资源不只是这三种维度,还有11种类型 。
锁对象
关于锁对象的说明
AllocUnit
分配单元
Application
应用程序专用的资源
Database
整个数据库
Extent
一组连续的8个页
File
数据库文件
Heap/B-tree
堆或者B树
Key
索引上的某一行
Metadata
元数据
Object
表、存储过程、视图等包括所有的数据和索引
OIB
用于联机索引构建时的锁
Page
数据库上8KB页
RID
堆上的某一行
RowGroup
列存储索引行组的时候使用的锁
Xact
事务的锁定资源
了解了数据库的锁及其锁定对象,那么日常使用的select、insert和update语句到底是如何应用这些概念呢?
SQL Server执行Select时使用的锁首先通过建表脚本创建一个数据库表:
USE [Test]GO/****** Object:Table [dbo].[UserTable]Script Date: 2022/6/29 20:08:23 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[UserTable]( [id] [varchar](36) NOT NULL, [name] [varchar](256) NULL, [code] [varchar](256) NULL, [createtime] [datetime] NULL, [lastmodifytime] [datetime] NULL,PRIMARY KEY CLUSTERED ( [id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]) ON [PRIMARY]GOUSE [Test]GOINSERT [dbo].[UserTable] ([id], [name], [code], [createtime], [lastmodifytime]) VALUES (N'5E4B68B0-71B8-43FB-B6B4-8E9D43A30589', N'test1', N'123456', CAST(N'2022-06-29T18:02:21.517' AS DateTime), CAST(N'2022-06-29T18:02:21.517' AS DateTime))GO


推荐阅读