MS SQL дедлок записей при использовании курсора и транзакции

Задача обновления определенных полей была выполнена при помощи следующего скрипта

Declare @data TABLE([Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY)
INSERT INTO @data VALUES ('Id'); --ключ записи, которую мы обновляем

DECLARE @Errors TABLE(ErrorMessage NVARCHAR(max) NULL)

DECLARE @work NVARCHAR(10)
SET @work = 'work'
BEGIN TRAN @work --открываем транзакцию

DECLARE dataCursore CURSOR
FOR SELECT Id FROM @data OPEN dataCursore

DECLARE @counter INT
DECLARE @success INT
DECLARE @contract UNIQUEIDENTIFIER
SET @counter = 0
SET @success = 0
FETCH NEXT FROM dataCursore INTO  @contract
WHILE @@FETCH_STATUS = 0
BEGIN
SET @counter = @counter + 1
 PRINT @counter
 PRINT @contract
 BEGIN TRY
    BEGIN
        UPDATE [db].[Table1]
        SET 
            [Field1] = JSON_MODIFY([Field1], '$.Document', NULL),
            [Field2] = JSON_MODIFY([Field2], '$.Document', NULL)
            WHERE [Id] = @contract
            SET @success = @success + 1
        END
 END TRY
 BEGIN CATCH
    INSERT INTO @Errors VALUES (CAST(@contract AS NVARCHAR(90)) + ' ' + ERROR_MESSAGE())
 END CATCH
FETCH NEXT FROM dataCursore INTO  @contract
END
CLOSE dataCursore
DEALLOCATE dataCursore
SELECT @counter AS final_count
SELECT @success AS succesfull_updates

IF (@counter != @success)
    BEGIN
        ROLLBACK TRAN @work
        PRINT 'Отмена изменений'
    END
ELSE
    BEGIN
        COMMIT TRAN @work
        PRINT 'Применение изменений'
    END

SELECT * FROM @Errors

Однако, после выполнения данного скрипта на боевой базе была получена информация, что служба, которая работала с обновленными записями не может их обработать. В связи с тем, что провести изучение проблемы мы не можем из-за отсутствия доступов к продуктовой базе, прошу ваших советов.


Ответы (1 шт):

Автор решения: RustySkull

Проблема заключалась в том, что по неизвестным причинам, закрытие и высвобожднение курсора ДО того, как вызывался коммит/роллбек вызывала дедлок записей.

Причины данного поведения пока не выявили.

Проще говоря, кусок

CLOSE dataCursore
DEALLOCATE dataCursore

должен находиться ПОСЛЕ

IF (@counter != @success)
    BEGIN
        ROLLBACK TRAN @work
        PRINT 'Отмена изменений'
    END
ELSE
    BEGIN
        COMMIT TRAN @work
        PRINT 'Применение изменений'
    END
→ Ссылка