我必须在遗留数据库的表中插入一些记录,并且由于其他古老系统使用它,因此更改表不是解决方案。
问题是目标表有一个 int 主键但没有标识规范。所以我必须找到下一个可用的 ID 并使用它:
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
了相同的结果...
关于如何确保我获得下一个 id 并使用它而不冒其他人(或我!)被冲洗掉的风险,有什么好的建议吗?
很抱歉之前没有提到这一点,但这是一个 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 的回答以及所有其他做出贡献的人!惊人的!