Потому что, когда 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];