Мне нужно вставить некоторые записи в таблицу в устаревшей базе данных, и, поскольку она используется в других древних системах, изменение таблицы не является решением.
Проблема в том, что у целевой таблицы есть первичный ключ int, но нет идентификатора идентификации. Поэтому я должен найти следующий доступный идентификатор и использовать его:
select @id=ISNULL(max(recid)+1,1) from subscriber
Однако я хочу запретить другим приложениям вставлять в таблицу, когда я делаю это, чтобы у нас не было никаких проблем. Я попробовал это:
begin transaction
declare @id as int
select @id=ISNULL(max(recid)+1,1) from subscriber WITH (HOLDLOCK, TABLOCK)
select @id
WAITFOR DELAY '00:00:01'
insert into subscriber (recid) values (@id)
commit transaction
select * from subscriber
в двух разных окнах в SQL Management Studio, и одна транзакция всегда уничтожается как жертва тупика.
Я тоже сначала попробовал SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
с тем же результатом ...
Любые хорошие предложения о том, как я могу обеспечить получение следующего идентификатора и использовать его, не рискуя, что кто-то еще (или я!) Попадет под охоту?
Извините, что не упомянул об этом раньше, но это сервер SQL 2000, поэтому я не могу использовать такие вещи, как FOR UPDATE и OUTPUT
ОБНОВЛЕНИЕ : Это решение, которое сработало для меня:
BEGIN TRANSACTION
DECLARE @id int
SELECT @id=recid
FROM identities WITH (UPDLOCK, ROWLOCK)
WHERE table_name = 'subscriber'
waitfor delay '00:00:06'
INSERT INTO subscriber (recid) values (@id)
UPDATE identities SET recid=recid+1
WHERE table_name = 'subscriber'
COMMIT transaction
select * from subscriber
WAITFOR позволяет мне иметь несколько соединений и запускать запрос несколько раз, чтобы вызвать параллелизм.
Спасибо Quassnoi за ответ и всем вам, ребята, которые внесли свой вклад! Отлично!