Потому что, когда XACT_ABORT ВЫКЛЮЧЕН (по умолчанию):
Когда SET XACT_ABORT имеет значение OFF, в некоторых случаях выполняется откат только инструкции 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];
person
gotqn
schedule
06.11.2019
XACT_ABORT
равноOFF
, потому что нарушение повторяющегося ключа прерывает только вторую вставку, а не транзакцию в целом, поэтомуCOMMIT
все еще происходит. Если вы сначала сделаетеSET XACT_ABORT ON
, фиксация не произойдет. Точные правила того, что прерывает и не прерывает транзакцию, действительно сложны, даже еслиXACT_ABORT
может значительно упростить ситуацию. - person Jeroen Mostert   schedule 06.11.2019