2016-09-09 37 views
1

我一直在尋找到這兩個問題:SQL服務器什麼時候回滾一個錯誤的事務?

SQL Server - transactions roll back on error?

sql transaction don't roll back

從我的研究,我得出這樣的查詢應該這樣寫的結論:

set XACT_ABORT ON 
begin tran FB5773_1 
begin try 
    -- Do some changes 
    commit tran FB5773_1; 
end try 
begin catch 
    IF EXISTS (SELECT [name] FROM sys.dm_tran_active_transactions WHERE name = 'FB5773_1') 
     rollback tran FB5773_1; 
end catch 

然而,我想知道爲什麼像這樣的交易

begin tran FB5773_1 
--do some stuff 
commit tran FB5773_1; 

或本

set XACT_ABORT ON 
begin tran FB5773_1 
--do some stuff 
commit tran FB5773_1; 

在錯誤某些情況下,不rollbacking,什麼是案件時,他們沒有rollbacking?

+0

這樣的事務使事務中的所有單個語句成爲原子整體。他們都成功了,或者他們都失敗了。並非所有事情都需要明確回退,但有時候需要一切東西來隔離,而你正在處理更大整體的單個較小塊。 –

+0

如果在提交事務之前發生了錯誤,我預計事務會回滾,但是,有人對事務非常瞭解告訴我這並非總是如此,並指向我一個url(http://stackoverflow.com/questions/) 1749719/sql-server-transactions-roll-on-error),其中有114次提示的答案告訴我們:「你可以在你的事務之前放置xact_abort,以確保sql在錯誤的情況下自動回滾」。因此,我的行爲不清楚。 –

+0

在某些情況下,您不希望自動回滾,因爲您可能會根據錯誤來決定行動方案。如果事情是自動回滾的,你不能做這個分支決定。 –

回答

1

我認爲你正在尋找的答案可以在微軟的文檔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在某些情況下可能非常有用,但開發人員需要了解潛在影響和限制,然後才能依靠所有情況下的設置來處理回滾。

+0

btberry,謝謝,這是一個輝煌而雄辯的答案。 –