Reputation: 71
By definition T-SQL transaction should be cancelled if any statement inside it results with error. However, I stumbled upon the situation where transaction passes with an error happening in the middle of it.
Example environment setup:
--test tables:
IF OBJECT_ID('t2', 'U') IS NOT NULL
DROP TABLE t2;
GO
IF OBJECT_ID('t1', 'U') IS NOT NULL
DROP TABLE t1;
GO
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY);
CREATE TABLE t2 (a INT NOT NULL REFERENCES t1(a));
GO
INSERT INTO t1
VALUES (1), (3), (4), (6);
GO
Transaction test:
BEGIN TRANSACTION
INSERT INTO t2 VALUES (1);
INSERT INTO t2 VALUES (2); -- Foreign key error will be thrown.
INSERT INTO t2 VALUES (3);
COMMIT TRANSACTION;
This should have been cancelled because of the foreign key error, but it isn't:
SELECT * FROM t2;
results with two rows returned - values 1 and 3.
Adding SET XACT_ABORT ON
does the job, but how is it possible that entire transaction holds up when there's an error in the middle of it?
Upvotes: 0
Views: 369
Reputation: 46203
Depending on the specific error, the T-SQL batch will continue after an error without XACT_ABORT ON
. I recommend TRY/CATCH
with IF @@TRANCOUNT > 0 ROLLBACK;
in the CATCH BLOCK
plus XACT_ABORT ON
to make sure the rollback occurs immediately in the case of a query cancel or client timeout (which prevents the CATCH
block from being executed):
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO t2 VALUES (1);
INSERT INTO t2 VALUES (2); -- Foreign key error will be thrown.
INSERT INTO t2 VALUES (3);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK;
END CATCH;
Upvotes: 2