Что делать, если мой триггер завершается с ошибкой после обновления внутри хранимой процедуры?

#sql-server #stored-procedures #triggers

#sql-server #хранимые процедуры #триггеры

Вопрос:

Однако, если у меня есть обновление внутри хранимой процедуры в SQL Server, и хранимая процедура выполняется успешно, триггер для этого обновления по какой-либо причине завершается с ошибкой, будет ли мое обновление откатываться?

Комментарии:

1. Это зависит от различных настроек. Покажите ваш фактический код (сократите до соответствующих частей).

2. Вы хотите прочитать о XACT_ABORT , который включен по умолчанию для триггера, но может быть отключен.

3. Мне еще предстоит написать код, но я пытаюсь учесть это раньше.

Ответ №1:

Да, если в вашем триггере произойдет откат или какая-либо ошибка во время выполнения, он откатит конкретную (или подразумеваемую) транзакцию над ней.

Чтобы увидеть, что это произойдет при обновлении, о котором вы спрашиваете, запустите это:

 DROP TABLE IF EXISTS dbo.MyTable;
DROP TABLE IF EXISTS dbo.OtherTable;
GO

CREATE TABLE dbo.MyTable (ID INT);
GO
CREATE TABLE dbo.OtherTable (ID INT);
GO

CREATE TRIGGER dbo.UpdateTrigger
ON dbo.MyTable
FOR  UPDATE
AS 
BEGIN
      INSERT dbo.OtherTable (ID) VALUES ('Blah');
END;
GO

INSERT dbo.MyTable (ID) VALUES (1);
GO

UPDATE dbo.MyTable SET ID = 2;
GO

SELECT ID FROM dbo.MyTable;
SELECT ID FROM dbo.OtherTable;
  

Вы увидите, что значение ID в MyTable по-прежнему равно 1, а OtherTable по-прежнему пуст, потому что триггер выдал ошибку во время ОБНОВЛЕНИЯ.

Даже если вы установите XACT_ABORT OFF в триггере и в пакете обновления, обновление все равно будет откатываться.

 DROP TABLE IF EXISTS dbo.MyTable;
DROP TABLE IF EXISTS dbo.OtherTable;
GO

CREATE TABLE dbo.MyTable (ID INT);
GO
CREATE TABLE dbo.OtherTable (ID INT);
GO

CREATE TRIGGER dbo.UpdateTrigger
ON dbo.MyTable
FOR  UPDATE
AS 
BEGIN
      SET XACT_ABORT OFF;
      INSERT dbo.OtherTable (ID) VALUES ('Blah');
END;
GO

INSERT dbo.MyTable (ID) VALUES (1);
GO

SET XACT_ABORT OFF;
UPDATE dbo.MyTable SET ID = 2;
GO

SELECT ID FROM dbo.MyTable;
SELECT ID FROM dbo.OtherTable;
  

Если вы хотите продолжить ОБНОВЛЕНИЕ, даже если триггер завершается с ошибкой, вам следует использовать TRY / CATCH в вашем триггере для обработки ошибки времени выполнения и разрешить триггеру завершиться.