con*_*att 7 database sql-server sql-server-2016
我有下表:
CREATE TABLE [dbo].[table1](
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [nvarchar](50) NULL,
CONSTRAINT [PK_table1] 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]
GO
Run Code Online (Sandbox Code Playgroud)
我正在学习SQL锁是如何工作的,我正在尝试测试一种情况,我想锁定一行不被读取和更新.从这篇文章开始,这个任务的一些灵感,这是我试图解决的原始问题.
当我运行这个T-SQL时:
BEGIN TRANSACTION
SELECT * FROM dbo.table1 WITH (UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:15'
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)
我希望在表上放置一个独占锁,特别是对于行(如果我在主键上有一个WHERE语句)
但运行此查询,我可以看到GRANTed LOCK用于请求模式IX.
SELECT * FROM sys.dm_tran_locks WHERE resource_database_id = DB_ID() AND resource_associated_entity_id = OBJECT_ID(N'dbo.table1');
Run Code Online (Sandbox Code Playgroud)
此外,在单独的SSMS窗口中,我可以在事务运行时完全查询表.
为什么MSSQL不尊重锁定提示?
(SQL Server 2016)
编辑1
有关这些锁如何工作的任何信息,但是,当前的问题是SQL Server似乎没有强制执行我指定的锁.我的预感是,这与行版本控制或相关的东西有关.
编辑2
我创建了这个Github要点.它需要.NET和外部库Dapper才能运行(可通过Nuget包获得).
这是我注意到的有趣的事情:
table1即使UPDLOCK, HOLDLOCK已请求先前的查询,也可以运行SELECT语句.这是该Gist的控制台输出:
运行锁定SELECT开始 - 00:00:00.0165118
运行非锁定SELECT开始 - 00:00:02.0155787
运行非锁定SELECT完成 - 00:00:02.0222536
运行INSERT开始 - 00:00:04.0156334
运行更新全部开始 - 00: 00:06.0259382
运行更新现有开始 - 00:00:08.0216868
运行更新不存在开始 - 00:00:10.0236223
运行更新不存在完成 - 00:00:10.0268826
运行锁定SELECT完成 - 00:00:31.3204120
运行INSERT完成- 00:00:31.3209670
运行更新全部完成 - 00:00:31.3213625
运行更新现有完成 - 00:00:31.3219371
我正在尝试测试一种情况,我想锁定一行不被读取和更新
如果要锁定一行不被读取和更新,则需要独占锁,但UPDLOCK锁提示请求更新锁,而不是独占锁。查询应该是:
SELECT * FROM table1 WITH (XLOCK, HOLDLOCK, ROWLOCK)
WHERE Id = <some id>
Run Code Online (Sandbox Code Playgroud)
此外,在READ COMMITTED SNAPSHOT和SNAPSHOT隔离级别下,SELECT语句不请求共享锁,只请求架构稳定性锁。因此,SELECT尽管存在排他锁,该语句仍可以读取该行。令人惊讶的是,在 READ COMMITTED 隔离级别下,SELECT 语句可能不会请求行级共享锁。您需要向SELECT语句添加查询提示以防止它读取锁定的行:
SELECT * FROM dbo.Table1 WITH (REPEATABLEREAD)
WHERE id = <some id>
Run Code Online (Sandbox Code Playgroud)
使用REPEATABLEREAD锁提示,该SELECT语句将请求共享锁并在事务期间保留它们,因此它不会读取独占锁定的行。请注意,仅使用READCOMMITTEDLOCK是不够的,因为在某些情况下 SQL Server 可能不会请求共享锁,如此博客文章中所述。
请查看锁兼容性表
在默认隔离级别下READ COMMITTED,并且没有锁提示,SELECT语句为其读取的每一行请求共享锁,并且这些锁在读取该行后立即释放。但是,如果您使用WITH (HOLDLOCK),则共享锁将一直保持到事务结束为止。考虑到表的锁兼容性,SELECT在 下运行的语句READ COMMITTED可以读取任何未独占锁定(IX、SIX、X 锁)的行。INSERT独占锁由、UPDATE和DELETE语句或SELECT带有提示的语句请求XLOCK。
我希望在表上放置一个独占锁,特别是针对该行(如果我在主键上有一个 WHERE 语句)
我需要了解为什么 SQL Server 不尊重给予它的锁定指令。(即为什么表或行上没有独占锁?)
UPDLOCKhint 不请求独占锁,它请求更新锁。此外,可以在行本身以外的其他资源上授予锁,也可以在表、数据页、索引页和索引键上授予锁。SQL Server 可以锁定的资源类型的完整列表是:DATABASE, FILE, OBJECT, PAGE, KEY, EXTENT, RID, APPLICATION, METADATA, HOBT, and ALLOCATION_UNIT。当ROWLOCK指定hint时,SQL Server将锁定行,而不是页、范围或表,并且SQL Server将锁定的实际资源是RID和KEY'
小智 1
@Remus Rusuanu 的解释比我在这里解释得更好。
本质上 - 你总是可以阅读,除非你要求相同的锁类型(或更严格)。但是,如果您愿意,UPDATE否则DELETE您将被阻止。但正如我所说,上面的链接解释得很好。
| 归档时间: |
|
| 查看次数: |
667 次 |
| 最近记录: |