Какой лучший способ заблокировать запись во время ее обновления? - PullRequest
1 голос
/ 04 января 2011

Если мне нужно SELECT значение из столбца таблицы (случается, это столбец первичного ключа), основанное на относительно сложном предложении WHERE в хранимой процедуре, и я затем хочу обновить эту запись без каких-либо другиходновременные хранимые процедуры SELECT с одной и той же записью, это так же просто, как просто использовать транзакцию?Или мне также нужно повысить изоляцию до Repeatable Read?

Это выглядит так:

Alter Procedure Blah
As
Declare @targetval int
update table1 set field9 = 1, @targetval = field1 where field1 = (
SELECT TOP 1 field1
FROM table1 t
WHERE
(t.field2 = 'this') AND (t.field3 = 'that') AND (t.field4 = 'yep') AND (t.field9 <> 1))
return

Затем я получаю свой targetval в своей программе, чтобы я мог работать над ним,и в то же время мне не нужно беспокоиться о том, что другие рабочие потоки захватывают один и тот же targetval.

Я говорю о SQL 2000, SQL 2005 и SQL 2008 здесь.

1 Ответ

2 голосов
/ 04 января 2011

Добавление ROWLOCK,UPDLOCK к подзапросу должно сделать это.

ALTER PROCEDURE Blah
AS
  DECLARE @targetval INT

  UPDATE table1
  SET    field9 = 1,
         @targetval = field1
  WHERE  field1 = (SELECT TOP 1 field1
                   FROM   table1 t WITH (rowlock, updlock)
                   WHERE  ( t.field2 = 'this' )
                          AND ( t.field3 = 'that' )
                          AND ( t.field4 = 'yep' )
                          AND ( t.field9 <> 1 ))

  RETURN  

Обновлено

В настоящее время принятый ответ на этот вопрос не использует updlock. Я совсем не уверен, что это будет работать. Насколько я вижу из тестирования в запросе этого типа с подзапросом, SQL Server будет принимать только S блокировок для подзапроса. Однако иногда подзапрос будет оптимизирован, поэтому этот подход может работать так же, как и в Query 2.

Тестовый скрипт - Настройка

CREATE TABLE test_table
(
id int identity(1,1) primary key,
col char(40)
)

INSERT INTO test_table
SELECT NEWID() FROM sys.objects

Запрос 1

update test_table
set col=NEWID()
where id=(SELECT top (1) id from test_table )

Plan for id query Trace for id query

Запрос 2

update test_table
set col=NEWID()
where id=(SELECT max(id) from test_table)

Plan for max query Trace for max query

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...