這是從When I update/insert a single row should it lock the entire table?爲什麼行級別鎖定不能在SQL Server中正常工作?
的延續這是我的問題。
我有一張容納鎖的表,以便系統中的其他記錄不必鎖定公共資源,但仍可以排列任務,以便一次執行一個任務。
當我訪問此鎖表中的一條記錄時,我希望能夠鎖定它並更新它(只是一條記錄),而不需要其他任何進程都可以做同樣的事情。我可以通過鎖定提示來執行此操作,例如Uplock。
雖然會發生什麼情況是,即使我使用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
一個鎖添加兩行鎖名稱= 'A',一個用於鎖名稱= '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把鎖是該行問題和鎖名稱=任何後續查詢」 A」將不得不等待。這種行爲是正確的。
如果這變得有點令人沮喪的是,當你運行你被阻塞,直到查詢1個完成甚至認爲這是不相關的記錄查詢2。如果您再運行查詢1就像我上面那樣,它會提交上一個事務,查詢2將運行,然後查詢1將再次鎖定記錄。
請提供一些建議,告訴我如何才能正確鎖定只有一行,並且不會阻止更新其他項目。
PS。更新其中一行後,Holdlock也無法產生正確的行爲。
這是一個很好的答案,並感謝您發佈有用的代碼。有沒有辦法讓SQL默認這種模式? – Middletone 2010-02-25 16:27:32
@Middletone:什麼是「默認」? – Quassnoi 2010-02-25 16:28:22
對不起,我真的應該問如何讓SQL使用索引而不是表掃描,因爲這聽起來有點像是什麼導致它不使用表上的索引。有沒有辦法讓它始終鎖定主鍵,而不管它如何在表中找到記錄?這是我對違約的看法。 – Middletone 2010-02-25 16:36:52