Правильне використання транзакцій у SQL Server


236

У мене є 2 команди, і потрібно, щоб обидві вони були виконані правильно або жодна з них не виконувалася. Тому я думаю, що мені потрібна транзакція, але я не знаю, як правильно її використовувати.

У чому проблема із наступним сценарієм?

BEGIN TRANSACTION [Tran1]

INSERT INTO [Test].[dbo].[T1]
    ([Title], [AVG])
VALUES ('Tidd130', 130), ('Tidd230', 230)

UPDATE [Test].[dbo].[T1]
  SET [Title] = N'az2' ,[AVG] = 1
  WHERE [dbo].[T1].[Title] = N'az'

COMMIT TRANSACTION [Tran1]
GO

INSERTКоманда виконується, але UPDATEкоманда має проблему.

Як я можу реалізувати це для відкату обох команд, якщо будь-яка з них має помилку у виконанні?

Відповіді:


513

Додайте блок "спробувати / ловити", якщо транзакція пройде успішно, вона вчинить зміни, якщо транзакція не вдасться, транзакція буде відкатана:

BEGIN TRANSACTION [Tran1]

  BEGIN TRY

      INSERT INTO [Test].[dbo].[T1] ([Title], [AVG])
      VALUES ('Tidd130', 130), ('Tidd230', 230)

      UPDATE [Test].[dbo].[T1]
      SET [Title] = N'az2' ,[AVG] = 1
      WHERE [dbo].[T1].[Title] = N'az'

      COMMIT TRANSACTION [Tran1]

  END TRY

  BEGIN CATCH

      ROLLBACK TRANSACTION [Tran1]

  END CATCH  

1
Не BEGIN TRANSACTION [Tran1]слід розміщувати всередині TRY? У будь-якому випадку - дуже простий і елегантний фрагмент коду.
Piotr Nawrot

4
@PiotrNawrot Ні, якщо створення транзакції не вдалося, немає необхідності відкидати її в улов.
Монсеньйор

114

На початку збереженої процедури слід встановити SET XACT_ABORT ON, щоб доручити Sql Server автоматично здійснювати відкат транзакцій у разі помилки. Якщо заборонено або встановлено значення ВИМКНЕНО, потрібно перевірити @@ ПОМИЛКУ після кожного оператора або використати блок відкату TRY ... CATCH .


2
Іншими словами, ваша транзакція не є атомною, якщо ви спочатку не встановите XACT_ABORT.
4:00

З URL-адресою важко XACT_ABORT
розібратися

32

Легкий підхід:

CREATE TABLE T
(
    C [nvarchar](100) NOT NULL UNIQUE,
);

SET XACT_ABORT ON -- Turns on rollback if T-SQL statement raises a run-time error.
SELECT * FROM T; -- Check before.
BEGIN TRAN
    INSERT INTO T VALUES ('A');
    INSERT INTO T VALUES ('B');
    INSERT INTO T VALUES ('B');
    INSERT INTO T VALUES ('C');
COMMIT TRAN
SELECT * FROM T; -- Check after.
DELETE T;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.