1

我正在測試以查看嵌套事務如何工作,並發現了這種令人不安和意外的行爲。即使從未調用TransactionScope.Complete(),爲什麼還要提交嵌套事務?

using(TransactionScope otx = new TransactionScope()) 
using(SqlConnection conn1 = new SqlConnection("Server=S;Database=DB;Trusted_Connection=yes")) 
using(SqlCommand cmd1 = conn1.CreateCommand()) 
{ 
    conn1.Open(); 
    cmd1.CommandType = CommandType.Text; 
    cmd1.CommandText = "INSERT INTO FP.ACLs (ChangeToken,ACL) VALUES (1,0x)"; 
    cmd1.ExecuteNonQuery(); 

    using(TransactionScope itx = new TransactionScope(TransactionScopeOption.RequiresNew)) 
    using(SqlConnection conn2 = new SqlConnection("Server=S;Database=DB;Trusted_Connection=yes")) 
    using(SqlCommand cmd2 = conn1.CreateCommand()) 
    { 
     conn2.Open(); 
     cmd2.CommandType = CommandType.Text; 
     cmd2.CommandText = "INSERT INTO FP.ACLs (ChangeToken,ACL) VALUES (2,0x)"; 
     cmd2.ExecuteNonQuery(); 
     // we don't commit the inner transaction 
    } 

    otx.Complete(); // nonetheless, the inner transaction gets committed here and two rows appear in the database! 
} 

我看到this other question,但該解決方案並不適用。

如果我沒有指定TransactionScopeOption.RequiresNew(即我沒有使用嵌套事務,只是一個嵌套的作用域),那麼整個事務將在內部作用域未完成時回滾,並且在發生錯誤時調用otx.Complete()。這可以。

但我當然不希望嵌套事務在未成功完成時被提交!有人知道這裏發生了什麼,我怎麼能得到預期的行爲?

數據庫是SQL Server 2008 R2。

+0

如果你打算每個查詢使用一個TransactionScope,你爲什麼要使用它們? – 2011-05-31 12:04:09

回答

0

您的第二個命令對象是在conn1而不是conn2上創建的,所以它非常類似於其他問題 - 在第二個事務作用域打開之前,您正在其上運行命令的連接已打開。

6

首先,有no such thing as a nested transaction in SQL Server。這個很重要。

其次,無論TransactionScopes使用conn1就等你(在SQL Server級別),每個BEGIN TRANSACTION

簡單的解釋遞增@@TRANCOUNT:當外部事務提交,因爲回滾內將回滾內部事務被提交既交易

也就是說,COMMIT TRANSACTION(由.Complete.Dispose暗示)遞減@@TRANCOUNTROLLBACK TRANSACTION(由.Dispose暗示只)需要回零。所以內部回滾被抑制是因爲「沒有嵌套事務這樣的東西」

如果您在內部範圍內正確使用了conn2,它將按預期工作,因爲這兩個事務在數據庫服務器級別無關。這是重要的地方......

相關問題