Почему следующая транзакция t-sql не работает должным образом? - PullRequest
1 голос
/ 06 ноября 2019

Чтобы проверить, как работает транзакция, я написал следующее t-sql. Поскольку первый атрибут является первичным ключом, ни одна из вставок не должна быть зафиксирована. Но первая вставка совершена? Почему?

begin transaction
   insert into instructor
   values ('99999', 'Yellow', 'Biology', 700000)

   insert into instructor
   values ('99999', 'Blue', 'Statistics', 85000)
commit;

select * from instructor where ID = '99999'

--delete from instructor where ID = '99999'

(затронута 1 строка) Сообщение 2627, уровень 14, состояние 1, строка 100 Нарушение ограничения PRIMARY KEY 'PK__instruct__3214EC278C8DA99F'. Невозможно вставить дубликат ключа в объект 'dbo.instructor'. Значение дубликата ключа (99999). Оператор был расторгнут.

Время завершения: 2019-11-06T14: 02: 27.3436411 + 02: 00

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

Вам необходимо добавить SET XACT_ABORT ON; и / или использовать TRY / CATCH, чтобы сценарий не продолжал до COMMIT после ошибки.

SET XACT_ABORT ON пример:

SET XACT_ABORT ON;
begin transaction
   insert into instructor
   values ('99999', 'Yellow', 'Biology', 700000)

   insert into instructor
   values ('99999', 'Blue', 'Statistics', 85000)
commit;

Пример TRY / CATCH:

BEGIN TRY
    begin transaction
       insert into instructor
       values ('99999', 'Yellow', 'Biology', 700000)

       insert into instructor
       values ('99999', 'Blue', 'Statistics', 85000)
    commit;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK;
    THROW;
END CATCH;
0 голосов
/ 06 ноября 2019

Потому что, когда XACT_ABORT выключен (это значение по умолчанию):

Когда SET XACT_ABORT выключен, в некоторых случаях откатывается только оператор Transact-SQL, вызвавший ошибку, итранзакция продолжает обрабатываться.

и когда она равна ON:

.. если инструкция Transact-SQL вызывает ошибку во время выполнения, вся транзакция завершаетсяи откат.

Это то, что нам нужно, чтобы включить его ON, и если вы попробуете код ниже, вы можете проверить это:

DROP TABLE IF EXISTS [dbo].[StackOverflow];

CREATE TABLE [dbo].[StackOverflow]
(
    [StackID] TINYINT PRIMARY KEY
);

SET XACT_ABORT ON;

BEGIN TRANSACTION;

INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (105);

INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (105);

COMMIT TRANSACTION;

SET XACT_ABORT OFF;

SELECT [StackID]
FROM [dbo].[StackOverflow];

Также обратите внимание, что:

SET XACT_ABORT не влияет на ошибки компиляции, такие как синтаксические ошибки.

Вышесказанное означает, что если вы действительно хотите иметь автоматическую транзакцию, вам нужно использоватьследующий блок кода:

SET NOCOUNT, XACT_ABORT ON;

BEGIN TRY

    BEGIN TRANSACTION;
    -- CODE BLOCK GOES HERE
    COMMIT TRANSACTION;

END TRY
BEGIN CATCH 

   IF @@TRANCOUNT > 0
   BEGIN
      ROLLBACK TRANSACTION
   END;

   -- GET ERRORS DETAILS OR THROW ERROR

END CATCH;

SET NOCOUNT, XACT_ABORT OFF;

Если вы не используете блок TRY-CATCH в определенных ситуациях, например, в следующем, первый оператор будет снова зафиксирован:

DROP TABLE IF EXISTS [dbo].[StackOverflow];

CREATE TABLE [dbo].[StackOverflow]
(
    [StackID] TINYINT PRIMARY KEY
);

SET XACT_ABORT ON;

BEGIN TRANSACTION;

INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (105);

EXEC 
(
    'INSERrrrrrT INTO [dbo].[StackOverflow] ([StackID]) VALUES (106);'
)

COMMIT TRANSACTION;

SET XACT_ABORT OFF;

SELECT [StackID]
FROM [dbo].[StackOverflow];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...