Это продолжение от Когда я обновляю / вставляю одну строку, должна ли она блокировать всю таблицу?
Вот моя проблема.
У меня есть таблица, в которой хранятся блокировки, поэтому другим записям в системе не нужно снимать блокировки на общих ресурсах, но все равно можно ставить задачи в очередь, чтобы они выполнялись по одной за раз.
Когда я получаю доступ к записи в этой таблице блокировок, я хочу иметь возможность заблокировать ее и обновить ее (только одну запись) без какого-либо другого процесса, способного сделать то же самое. Я могу сделать это с помощью подсказки о блокировке, например 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'
Обратите внимание, что я оставляю транзакцию открытой, чтобы вы могли видеть эту проблему, поскольку она не была бы видна без этой открытой транзакции.
Когда вы запускаете Запрос 1 блокировки являются проблемами для строки, и любые последующие запросы для LockName = ’A’ должны будут ждать. Это правильное поведение.
Это немного расстраивает, когда вы запускаете Query 2 , и вы блокируетесь до тех пор, пока Query 1 не завершит работу, даже если это не связанные записи. Если вы затем снова выполните Query 1 , как я это сделал выше, он совершит предыдущую транзакцию, Query 2 будет запущен, а затем Query 1 будет снова заблокировать запись.
Пожалуйста, предложите несколько советов о том, как я мог бы сделать так, чтобы он правильно блокировал ТОЛЬКО одну строку и не препятствовал обновлению других элементов.
PS. Holdlock также не может произвести правильное поведение после обновления одной из строк.