这是When I update/insert a single row should it lock the entire table?的延续。
我遇到了一个问题。
我有一张表用于保存锁,这样系统中的其他记录就不必为常用资源申请锁,但仍然可以排队执行任务。
当我访问此锁表中的一条记录时,我想锁定并更新它(只更新一条记录),而不允许其他进程进行相同的操作。我可以使用像updlock这样的锁提示来实现这一点。
然而,尽管我使用了rowlock来锁定记录,但它阻止了另一个进程请求更改同一张表中完全无关的行,该进程也将指定updlock提示和rowlock。
您可以通过创建一个表来重新创建这个问题。
为锁添加两行,其中 LockName=‘A’ 一行,LockName=‘B’ 一行。
然后创建两个查询,在同一时间内进行事务处理: 查询1:
请注意,我保持交易开放,以便您可以看到此问题,因为如果没有这个开放的交易,它是不可见的。
当您运行“查询1”时,会为该行和任何后续查询“LockName ='A'”发出锁定,这种行为是正确的。
当您运行“查询2”时,即使这些记录不相关,您也会被阻止,直到“查询1”完成,这有点令人沮丧。如果您按照上面的方式再次运行“查询1”,它将提交上一个事务,“查询2”将运行,然后“查询1”将再次锁定该记录。
请提供一些建议,以便我能够正确锁定“仅”一个行,并防止其他项目被更新。
PS. 在其中一行被更新后,“Holdlock”也无法产生正确的行为。
我遇到了一个问题。
我有一张表用于保存锁,这样系统中的其他记录就不必为常用资源申请锁,但仍然可以排队执行任务。
当我访问此锁表中的一条记录时,我想锁定并更新它(只更新一条记录),而不允许其他进程进行相同的操作。我可以使用像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'
Query 2:
select * From Locks with (updlock rowlock) where LockName='B'
请注意,我保持交易开放,以便您可以看到此问题,因为如果没有这个开放的交易,它是不可见的。
当您运行“查询1”时,会为该行和任何后续查询“LockName ='A'”发出锁定,这种行为是正确的。
当您运行“查询2”时,即使这些记录不相关,您也会被阻止,直到“查询1”完成,这有点令人沮丧。如果您按照上面的方式再次运行“查询1”,它将提交上一个事务,“查询2”将运行,然后“查询1”将再次锁定该记录。
请提供一些建议,以便我能够正确锁定“仅”一个行,并防止其他项目被更新。
PS. 在其中一行被更新后,“Holdlock”也无法产生正确的行为。