SQL Server Insert操作中的锁

原文:SQL Server Insert操作中的锁

这篇博文简单介绍一下在SQL Server中一条Insert语句中用到的锁。

准备数据

首先我们建立一张表Table_1,它有两列Id(bigint)和Value(varchar),其中Id建立了主键。

CREATE TABLE [dbo].[Table_2](
    [Id] [bigint] NOT NULL,
    [Value] [nchar](10) NULL,
 CONSTRAINT [PK_Table_2] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

然后插入两条数据。

insert into dbo.table_2
(id, value)
values
(1, ‘1‘),
(2, ‘2‘);

开始测试

我们知道,在Transaction中共享锁在查询语句结束就释放了,而排它锁则在Transaction提交才释放。我们可以利用它来执行一个Insert,不提交Transaction,然后去查看锁的状态。注意,本文中查询窗口配置的Transaction隔离级别是默认值READ COMMITTED。

首先执行以下SQL:

begin tran t1

insert into dbo.table_2
(id, value)
values
(3, ‘3‘);

然后查看锁:

SELECT
    resource_type,
    request_mode,
    resource_description,
    request_session_id,
    request_status,
    resource_associated_entity_id,
    DB_NAME(resource_database_id)as resource_database
FROM
    sys.dm_tran_locks
WHERE
    resource_type <> ‘DATABASE‘
ORDER BY
    request_session_id;

执行结果如下:

  • 第一个是意向排他锁。它表示这个数据页下存在排他锁(就是第三个排他锁),我们发现它的resource_associated_entity_id和第三个锁一样。那么,这个数据页就是存放这行数据的这个主键的。
  • 第二个也是意向排他。它的resource_type是OBJECT,此对象可以是数据表、视图、存储过程、扩展存储过程或任何具有对象 ID 的对象。它的resource_associated_entity_id这一列其实是object_id, 用函数object_name(object_id)看一下发现结果是Table_2。那么它下面存在的排他锁指的也是第三个锁了。
  • 第三个是排他锁。resou_description指的是插入数据主键的哈希值。

补充1

此时,我们在另外一个命令窗口中执行以下查询语句不会产生阻塞:

SELECT *
FROM dbo.Table_2
WHERE id=1;

但另一条却会产生阻塞:

SELECT *
FROM dbo.Table_2
WHERE id=3;

来看看第一条SQL产生的锁。由于共享锁会在查询结束立即释放,因此我们加一个HOLDLOCK,让它在事务结束再释放:

begin tran t2

SELECT *
FROM dbo.Table_2 WITH(HOLDLOCK)
WHERE id=1;

这是执行完以上语句锁的情况:

第二条SQL会产生阻塞,因此可以直接查询然后看锁的情况:

我们发现第9行的resource_description和第3行是相同的,这也说明了主键的锁只是锁住了某一个值而已。

补充2

这条SQL也会被Insert阻塞:

SELECT
    value
FROM
    dbo.Table_2
WHERE
    value=‘1‘

而且查看当前的锁可以发现,Key被锁的值正是Insert语句的Key值。这里有两个疑问:1. 为什么没用到主键列,却产生了主键锁。2.为什么Insert的数据还未commit,这里却会产生这一行主键的锁。

答:1. 我们查看查询计划,可以看到这条语句是用了聚集索引扫描,至于为什么不是表扫描,请看这里。 2. 由于事务隔离级别默认是Read Committed,所以这里会对已插入但未提交的数据主键加一个共享锁。

时间: 2024-10-10 18:32:27

SQL Server Insert操作中的锁的相关文章

(转)SQL Server 的事务和锁(一)

SQL Server 的事务和锁(一) 最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT @findCount=COUNT(id) FROM MyTable WHERE [fk_related_id][email protected] IF (@findCount > 0) BEGIN     ROLLBACK TRANSACTION     RET

SQL Server里的自旋锁介绍

在上一篇文章里我讨论了SQL Server里的闩锁.在文章的最后我给你简单介绍了下自旋锁(Spinlock).基于那个基础,今天我会继续讨论SQL Server中的自旋锁,还有给你展示下如何对它们进行故障排除. 为什么我们需要自旋锁? 在上篇文章我已经指出,用闩锁同步多个线程间数据结构访问,在每个共享数据结构前都放置一个闩锁没有意义的.闩锁与此紧密关联:当你不能获得闩锁(因为其他人已经有一个不兼容的闩锁拿到),查询就会强制等待,并进入挂起(SUSPENDED)状态.查询在挂起状态等待直到可以拿到

SQL Server里的闩锁介绍

在今天的文章里我想谈下SQL Server使用的更高级的,轻量级的同步对象:闩锁(Latch).闩锁是SQL Server存储引擎使用轻量级同步对象,用来保护多线程访问内存内结构.文章的第1部分我会介绍SQL Server里为什么需要闩锁,在第2部分我会给你介绍各个闩锁类型,还有你如何能对它们进行故障排除. 为什么我们需要闩锁? 闩锁首次在SQL Server 7.0里引入,同时微软首次引入了行级别锁(row-level locking).对于行级别锁引入闩锁的概念是非常重要的,不然的话在内存中

SQL Server &#39;已超过了锁请求超时时段&#39; 问题解决方法

SQL 有时遇到 已超过了锁请求超时时段. (Microsoft SQL Server,错误: 1222) 这个错误,刷新以后,右击某张表或者库,发现里面的表全部消失了 或者查询不到. 这是因为 sql进程死锁,资源被抢占,要解决这个问题,得杀死关闭 死锁的进程,下面介绍解决方案: 杀死进程的前提是找到 那个死锁的进程 , SELECT blocking_session_id '阻塞进程的ID', wait_duration_ms '等待时间(毫秒)', session_id '(会话ID)'

SQL Server 的事务和锁(一)

最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT @findCount=COUNT(id) FROM MyTable WHERE [fk_related_id][email protected] IF (@findCount > 0) BEGIN     ROLLBACK TRANSACTION     RETURN ERROR_CODE END I

SQL Server 的事务和锁(二)-Range S-S锁

在这篇随笔中,我们的主要关注点在 Key-Range Lock.Key-Range Lock有 S-S.S-U.I-N.X-X几种情况.我们一个一个来说,力求明白.遗憾的是,这里可能会比较冗长,那么死锁分析只好依次顺延了. Range S-S锁的获取规则 MSDN 对 Range 锁的规则有部分描述,但是言简意赅,以下我们会将各种情况分解开来,理清MSDN中涉及的或者未涉及的规则,这些规则适用于SQL Server 2000/2005/2008/2008 R2.关于MSDN的描述,请参见:htt

SQL Server里的闩锁耦合(Latch Coupling)

几年前,我写了篇关于闩锁和为什么SQL Server需要它们的文章.在今天的文章里,我想进一步谈下非缓存区闩锁(Non-Buffer Latches),还有在索引查找操作期间,SQL Server如何使用它们.在这里你会学到称为闩锁耦合(Latch Coupling)的概念. 索引查找操作(Index Seek Operations) 正如你知道的,SQL Server使用扫描(Scan)和查找(Seek)操作在索引(聚集和非聚集索引)里访问数据.这里的查找操作使用B树的导航结构在叶子节点查找特

(转)SQL Server 的事务和锁(二)-Range S-S锁

在这篇随笔中,我们的主要关注点在 Key-Range Lock.Key-Range Lock有 S-S.S-U.I-N.X-X几种情况.我们一个一个来说,力求明白.遗憾的是,这里可能会比较冗长,那么死锁分析只好依次顺延了. Range S-S锁的获取规则 MSDN 对 Range 锁的规则有部分描述,但是言简意赅,以下我们会将各种情况分解开来,理清MSDN中涉及的或者未涉及的规则,这些规则适用于SQL Server 2000/2005/2008/2008 R2.关于MSDN的描述,请参见:htt

SQL server 2005中的锁(1)

在之前的一片随笔中,简单的说了一下SQL Server中的隔离级别.而SQL Server的隔离级别是通过锁的机制来实现的.现在深入一下,谈谈SQL Server中的锁. 开始之前,先要定义一下前提: 1.隔离级别的实现其实就是在不同的资源上加锁.2.对数据库的每一次访问(CRUD)我们称其为一个事务(在begin tran,commit tran|rollback tran中的语句块,或者即席查询--单条SQL).不同的事务如果同时访问同一个数据库资源,会产生一系列的问题(见Sql Serve