【发布时间】:2010-02-25 16:02:35
【问题描述】:
这是When I update/insert a single row should it lock the entire table?的延续
这是我的问题。
我有一个持有锁的表,这样系统中的其他记录就不必对公共资源进行锁定,但仍然可以将任务排队,以便一次执行一个。
当我访问此锁定表中的记录时,我希望能够锁定并更新它(仅一条记录),而没有任何其他进程能够执行相同操作。我可以通过 updlock 之类的锁定提示来做到这一点。
发生的情况是,即使我使用行锁来锁定记录,它也会阻止对另一个进程的请求,以更改同一个表中完全不相关的行,该行也将指定 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'
请注意,我将交易保持打开状态,以便您可以看到此问题,因为如果没有此打开的交易,它将不可见。
当您运行 Query 1 时,锁定是该行的问题,任何后续对 LockName='A' 的查询都必须等待。这种行为是正确的。
这有点令人沮丧的是,当您运行 Query 2 时,您会被阻止,直到 Query 1 完成,即使这些记录是不相关的记录。如果您然后像我上面那样再次运行 Query 1,它将提交上一个事务,Query 2 将运行,然后 Query 1将再次锁定记录。
请就我如何能够仅正确锁定一行而不阻止其他项目的更新提供一些建议。
PS。在更新其中一行后,Holdlock 也无法产生正确的行为。
【问题讨论】:
标签: sql-server tsql locking