博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SQL Server Insert操作中的锁
阅读量:6789 次
发布时间:2019-06-26

本文共 2005 字,大约阅读时间需要 6 分钟。

    这篇博文简单介绍一下在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]
View Code

 

    然后插入两条数据。

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

 

开始测试

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

    首先执行以下SQL:

begin tran t1insert 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_databaseFROM    sys.dm_tran_locksWHERE    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_2WHERE id=1;

但另一条却会产生阻塞:

SELECT *FROM dbo.Table_2WHERE id=3;

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

begin tran t2SELECT *FROM dbo.Table_2 WITH(HOLDLOCK)WHERE id=1;

 

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

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

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

补充2

这条SQL也会被Insert阻塞:

SELECT    valueFROM    dbo.Table_2WHERE    value='1'

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

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

转载于:https://www.cnblogs.com/szhx/p/4510922.html

你可能感兴趣的文章
App启动流程
查看>>
原理 | 分布式链路跟踪组件 SOFATracer 和 Zipkin 模型转换
查看>>
我的第一篇博客
查看>>
手把手教你如何用Python从PDF文件中导出数据(附链接)
查看>>
维珍银河完成最长距离火箭飞行,下一步剑指太空旅行
查看>>
[Python]attributeError:'module' object has no attribute 'dump'
查看>>
Docker系列教程11-使用Nexus管理Docker镜像
查看>>
业界最全,阿里云混合云灾备服务上线!
查看>>
Windows Linux 子系统可以在资源管理器中打开
查看>>
WebStorm文件类型关联设置
查看>>
13.1 Spring MVC 关于controller的字符编码
查看>>
理发店与 App 定价模型
查看>>
ES6(数组)
查看>>
php simplexml_load_file 函数执行不稳定
查看>>
C#,VB.NET如何将Word转换为PDF和Text
查看>>
玩转Kafka的生产者
查看>>
解决android.permission.WRITE_APN_SETTINGS
查看>>
py编程技巧-1.1-如何在列表、字典、集合中根据条件筛选数据
查看>>
Ruby on Rails: UUID as your ActiveRecord primary key
查看>>
Bean property属性说明
查看>>