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