为什么行级别锁定不能在SQL Server中正常工作?

这是从哪里更新/插入一行,如果它锁定整个表的延续?

这是我的问题。

我有一个存放锁的表,以便系统中的其他记录不必锁定公共资源,但仍可以排列任务,以便一次执行一个任务。

当我在这个锁表中访问一条记录时,我希望能够锁定它并更新它(仅仅是一条记录),而没有其他进程能够做到这一点。 我可以使用锁定提示(如updlock)来执行此操作

尽管我使用的是一个rowlock来锁定记录,但它会阻止对另一个进程的请求,以便在同一个表中更改完全不相关的行,该行也会指定updlock提示和rowlock

你可以重新创建一个表格

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Locks](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [LockName] [varchar](50) NOT NULL,
    [Locked] [bit] NOT NULL,
 CONSTRAINT [PK_Locks] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Locks] ADD  CONSTRAINT [DF_Locks_LockName]  DEFAULT ('') FOR [LockName]
GO
ALTER TABLE [dbo].[Locks] ADD  CONSTRAINT [DF_Locks_Locked]  DEFAULT ((0)) FOR [Locked]
GO

LockName ='A'LockName ='B'的锁添加两行

然后创建两个查询以同时在事务中运行:

查询1:

Commit
Begin transaction
select * From Locks with (updlock rowlock) where LockName='A'

查询2:

select * From Locks with (updlock rowlock) where LockName='B'

请注意,我将交易开放,以便您可以看到此问题,因为如果没有此公开交易,它将不可见。

当您运行查询1时,锁定是该行的问题,并且LockName ='A'的任何后续查询都必须等待。 这种行为是正确的。

在有些令人沮丧的情况下,当您运行查询2时,您会被阻止,直到查询1完成,即使认为这些记录不相关。 如果您再次运行Query 1 ,就像我上面那样,它将提交前一个事务, Query 2将运行,然后Query 1将再次锁定该记录。

请提供一些建议,我怎么可能能有得当锁定一行,不能阻止其他物品被更新。

PS。 更新其中一行后,Holdlock也无法产生正确的行为。


SQL Server ,锁提示应用于扫描的对象,不匹配。

通常,引擎在读取对象(页面等)时共享锁,并在完成扫描之后提升它们(或不在SERIALIZABLE事务中提升)。

但是,您指示引擎放置(并提起)彼此不兼容的更新锁。

事务B在尝试将UPDLOCK放入已由事务AUPDLOCK锁定的行时锁定。

如果你创建一个索引并强制使用它(所以不会发生冲突),你的表不会锁定:

CREATE INDEX ix_locks_lockname ON locks (lockname)

Begin transaction
select * From Locks with (updlock rowlock INDEX (ix_locks_lockname)) where LockName='A'

Begin transaction
select * From Locks with (updlock rowlock INDEX (ix_locks_lockname)) where LockName='B'

对于查询2,请尝试使用READPAST提示 - this(quote):

指定数据库引擎不读取被其他事务锁定的行。 在大多数情况下,页面也是如此。 当指定READPAST时,将跳过行级和页级锁。 也就是说,数据库引擎会跳过行或页面,而不是阻止当前事务,直到锁被释放

这通常用于队列处理类型的环境 - 因此多个进程可以从队列表中取出下一个项目,而不会被其他进程阻塞(当然,使用UPDLOCK可以防止多个进程拾取同一行)。

编辑1:
如果在LockName字段中没有索引,可能会导致这种情况。 通过索引,查询2可以对确切的行进行索引查找。 但是如果没有它,它将进行扫描(检查每一行),这意味着第一个事务会阻止它。 所以,如果它没有索引,尝试索引它。


我不确定你要完成什么,但通常那些处理类似问题的人想要使用sp_getapplock。 Tony Rogerson:通过创建自己的锁来协助并发(SQL中的互斥锁)

链接地址: http://www.djcxy.com/p/32829.html

上一篇: Why does row level locking not appear to work correctly in SQL server?

下一篇: What is the difference between varchar and nvarchar?