【发布时间】:2011-12-19 20:46:53
【问题描述】:
下面的 sproc 尝试在表中插入一行并生成一个随机 ID,该 ID 用于在相应表上进行 PK。具有随机生成的 ID 的冲突在 catch 块中处理,在该块中再次重试/调用该过程。现在,这需要很长时间并导致死锁,因为锁会保留很长时间。有没有办法在重试前立即解除死锁,以便其他线程可以成功锁定 PK 索引时有一个短暂的窗口?
CREATE PROCEDURE addPerson
(
@FirstName nvarchar(100),
@LastName nvarchar(100)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @PersonId int
-- generate random PersonId
-- this sproc can generate ids that already exist in the table
EXEC generateRandomPersonId @PersonId=@PersonId OUTPUT
BEGIN TRY
INSERT INTO [dbo].[Persons]
(
PersonId,FirstName,LastName
)
VALUES
(
@PersonId,@FirstName,@LastName
)
BEGIN CATCH
--
-- HOW TO RELEASE LOCKS HERE that are still held
-- for the previous INSERT statement?
--
DECLARE @ErrorNumber int, @ErrorMessage nvarchar(2048)
SELECT @ErrorNumber=ERROR_NUMBER(),
@ErrorMessage=ERROR_MESSAGE()
-- if a race condition happened and
-- PersonId happened to be picked already, retry all over again
IF (@ErrorNumber = 2601 OR @ErrorNumber = 2627 AND CHARINDEX(N'PK_Persons_PersonId', @ErrorMessage) > 0)
BEGIN
--
-- RETRYING HERE participates in a high possibility and
-- occurrence of deadlocks
--
EXEC addPerson @FirstName,@LastName
END
ELSE
-- some other error, rethrow it
EXEC rethrowError
END
END CATCH
END
GO
【问题讨论】:
-
这是用于商业或生产环境的产品吗?
-
为什么会有多个错误代码用于违反唯一约束?完全不懂SQL server,只是好奇
-
为什么不使用transactions?在
try之前开始事务并回滚您写comment_ HOW TO RELEASE ... . -
而且不需要递归,你可以重写程序并使用循环。请记住,递归会增加堆栈。
-
为什么不检查生成的 id 是否已经存在于表中之前尝试做和
INSERT?
标签: sql tsql sql-server-2008-r2 database-deadlocks