我認爲你正在尋找的答案可以在微軟的文檔XACT_ABORT中找到,我會嘗試用一些例子和其他資源來增強它。在我們開始之前,幾張桌子一起玩,以測試在不同情況下會發生什麼:
CREATE TABLE _key
(id INT PRIMARY KEY CLUSTERED);
GO
INSERT INTO _key VALUES (1), (2), (3);
GO
CREATE TABLE _table1
(table1id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, id INT NOT NULL);
GO
ALTER TABLE dbo._table1
ADD CONSTRAINT FK_table1 FOREIGN KEY (id) REFERENCES dbo._key (id);
GO
CREATE TABLE _table2
(table2id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, id INT NOT NULL);
GO
ALTER TABLE dbo._table2
ADD CONSTRAINT FK_table2 FOREIGN KEY (id) REFERENCES dbo._key (id);
GO
CREATE PROCEDURE _proc
AS
BEGIN
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo._table1 (id) VALUES(1); --valid insert
DECLARE @query NVARCHAR(MAX) = N'SELECT ** FROM dbo._table1;'
EXEC (@query); --will result in compile error
COMMIT TRANSACTION;
RETURN 0;
END
GO
而且,每個實例之間我清除出表,以避免對剛剛發生的事情有任何疑問:
TRUNCATE TABLE _table1;
TRUNCATE TABLE _table2;
我不認爲這是有關SET XACT_ABORT OFF
的結果,這是默認的狀態混亂,但我們去了一個例子僅僅是明確的......
SET XACT_ABORT OFF; --this command has no practical effect
BEGIN TRANSACTION;
INSERT INTO dbo._table1 (id) VALUES(1); --valid insert
INSERT INTO dbo._table2 (id) VALUES(4); --invalid insert
COMMIT TRANSACTION;
當我們るn這個SSMS中,我們看到了一個錯誤:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_table2". The conflict occurred in database "db", table "dbo._key", column 'id'.
當我們查詢,看看有什麼是_table1,我們看到,插入並隨後承諾,因爲XACT_ABORT不上記錄。這個結果是有道理的,因爲我們不會中止,但真正的問題是SQL Server在打開該選項時的行爲。現在同樣的查詢與不同的中止設置:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo._table1 (id) VALUES(1); --valid insert
INSERT INTO dbo._table2 (id) VALUES(4); --invalid insert
COMMIT TRANSACTION;
我們看到在SSMS相同的錯誤,但是這一次沒有插入_table1記錄,因爲整批得到回滾當SQL Server打運行 - 時間錯誤。這是從MS的文檔關鍵短語:
When SET XACT_ABORT is ON, if a Transact-SQL statement raises a run-time error, the entire transaction is terminated and rolled back.
Compile errors, such as syntax errors, are not affected by SET XACT_ABORT.
(另外,我用多個表以揭露和處理,如果插入或更新是從那些不同的表所做的XACT_ABORT不會回滾語句神話這個聲明是沒有根據的,也是不真實的,事務中的所有語句都會回滾,不管表是什麼)
那麼接下來最大的問題是:什麼時候整個批處理不會被滾動儘管XACT_ABORT被設置了嗎? Erland Sommarskog已經解決了這個問題,我可以更簡潔地(更早地)解決這個問題。已知的條件下,其XACT_ABORT ON不發生錯誤時回滾批次分別是:
- Errors you raise yourself with RAISERROR.
- Compilation errors (which normally terminate the scope) do not terminate the batch.
- Error 266, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing.
所以,舉例來說:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO dbo._table1 (id) VALUES(1); --valid insert
RAISERROR (N'omg the sky is falling!!!', 16, 1); --my own error
COMMIT TRANSACTION;
這仍然將導致記錄被插入,並承諾爲我的RAISERROR不會觸發回滾。同樣,我們可以碰上一個語法錯誤,不會回滾批次:
EXEC dbo._proc;
這是一個很好的問題,並強調了這一事實,沒有一個放之四海而皆準的解決辦法,以處理錯誤SQL Server。 XACT_ABORT在某些情況下可能非常有用,但開發人員需要了解潛在影響和限制,然後才能依靠所有情況下的設置來處理回滾。
這樣的事務使事務中的所有單個語句成爲原子整體。他們都成功了,或者他們都失敗了。並非所有事情都需要明確回退,但有時候需要一切東西來隔離,而你正在處理更大整體的單個較小塊。 –
如果在提交事務之前發生了錯誤,我預計事務會回滾,但是,有人對事務非常瞭解告訴我這並非總是如此,並指向我一個url(http://stackoverflow.com/questions/) 1749719/sql-server-transactions-roll-on-error),其中有114次提示的答案告訴我們:「你可以在你的事務之前放置xact_abort,以確保sql在錯誤的情況下自動回滾」。因此,我的行爲不清楚。 –
在某些情況下,您不希望自動回滾,因爲您可能會根據錯誤來決定行動方案。如果事情是自動回滾的,你不能做這個分支決定。 –