SQL Server Insert操做中的锁

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

准备数据

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

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]
View Code

 

    而后插入两条数据。函数

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

 

开始测试

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

    首先执行如下SQL:spa

begin tran t1

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

    而后查看锁:3d

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;

    执行结果以下:code

  • 第一个是意向排他锁。它表示这个数据页下存在排他锁(就是第三个排他锁),咱们发现它的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;

但另外一条却会产生阻塞:blog

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,因此这里会对已插入但未提交的数据主键加一个共享锁。

相关文章
相关标签/搜索