Прежде всего, я надеюсь, что эта процедура будет работать только в академической среде, а не в коммерческом продукте или реальной производственной среде.
Это подход:
- заменить рекурсию на петлю
- использование транзакций
CREATE PROCEDURE addPerson
(
@FirstName nvarchar(100),
@LastName nvarchar(100)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @doed bit
set @doed = 0
DECLARE @PersonId int
WHILE @doed = 0
BEGIN
-- generate random PersonId
-- this sproc can generate ids that already exist in the table
EXEC generateRandomPersonId @PersonId=@PersonId OUTPUT
BEGIN TRANSACTION ExceptionHandling
BEGIN TRY
INSERT INTO [dbo].[Persons]
(
PersonId,FirstName,LastName
)
VALUES
(
@PersonId,@FirstName,@LastName
)
COMMIT TRANSACTION ExceptionHandling
BEGIN CATCH
ROLLBACK TRANSACTION ExceptionHandling
--
-- 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
set @doed = 0
END
ELSE
-- some other error, rethrow it
set @doed = 1
EXEC rethrowError
END
END CATCH
END --end while
END
GO
отказ от ответственности: не проверено