簡體   English   中英

在事務范圍之外執行的查詢中,MSDTC事務被提升為分布式

[英]MSDTC transaction being promoted to distributed on query executed outside of transaction scope

我有一個SQL Server 2008數據庫有兩個表,使用一個.NET 4.5的應用程序TransactionScope兩個數據庫查詢,每個使用該共享一個連接字符串自己單獨的連接。

這段代碼工作正常:

internal static void Main(string[] args)
{
    string connStr = string.Format(
        "Data Source={0};Initial Catalog={1};" +
        "Integrated Security=True", "My DB Server", "My Database");

    using (var scope = new TransactionScope())
    {
        string query1 = "(actual query not relevant)";
        var ds = GetSqlServerDataSet(query1, connStr);
        string query2 = "(actual query not relevant)";
        var ds1 = GetSqlServerDataSet(query2, connStr);
        scope.Complete();
    }
}

private static System.Data.DataSet GetSqlServerDataSet(string usingQuery, 
    string usingConnectionString, 
    params System.Data.SqlClient.SqlParameter[] withParameters)
{
    using (var ds = new System.Data.DataSet())
    using (var conn = new System.Data.SqlClient.SqlConnection(usingConnectionString))
    using (var command = new System.Data.SqlClient.SqlCommand(usingQuery, conn))
    {
        command.Parameters.AddRange(withParameters);

        using (var adapter = new System.Data.SqlClient.SqlDataAdapter(command))
        {
            adapter.Fill(ds);
        }

        return ds;
    }
}

現在,如果我在范圍內拋出一個異常來測試回滾,那就是當東西變得奇怪的時候。 我正在使用我編寫的引用類庫來持久保存有關數據庫異常的信息。 它是相同類型的設置 - 相同的SQL Server,.NET版本,相同的ADO.NET代碼等。它只是寫入不同的數據庫。

以下是它的工作原理:我已將此方法添加到我的應用中:

private static void HandleUnhandledException(Object sender, System.UnhandledExceptionEventArgs e)
{
    ExceptionHandling.Core.Main.ProcessException((Exception) e.ExceptionObject);
    Environment.Exit(0);
}

我已將此行添加到Main方法的頂部:

AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;

現在當我拋出異常時,例如throw new Exception("blah"); scope.Complete()之前的Main右下角,它會自動跳轉到HandleUnhandledException ,其余的就像我上面所描述的那樣發生。 這會導致帶有消息的System.Transactions.TransactionManagerCommunicationException

已禁用分布式事務管理器(MSDTC)的網絡訪問。 請使用組件服務管理工具在MSDTC的安全配置中啟用DTC以進行網絡訪問。

這發生在我的類庫中調用Connection.Open()時。

那么這里發生了什么? 我知道錯誤告訴了我什么,我知道如何解決它 我的問題是為什么這首先發生 我認為using語句會在它HandleUnhandledException我的HandleUnhandledException方法之前回滾事務,因此這里不應該涉及兩個事務。 還是我錯了?

這是因為當你的HandleUnhandledException方法運行時 - 你仍然在using塊內部,它的finally部分還沒有運行。 使用此代碼驗證很容易:

class Program {
    static void Main(string[] args) {
        AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
        try {
            throw new Exception("test");
        }
        finally {
            Console.WriteLine("finally");
        }
    }

    private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) {
        Console.WriteLine("handle exception");
    }
}

哪個輸出:

handle exception
Unhandled exception: System.Exception: test ...
finally

您可能想要閱讀問題(以及來自Eric Lipper的評論)以討論相關行為。 但我認為原因與你的問題不太相關 - 我們可以說它只是這樣。

鑒於這些信息,您可以清楚地看到為什么會出現異常 - 您仍然處於未通信的事務范圍內並嘗試打開與不同數據庫的連接。

在您的情況下想到的一個解決方案是檢查我們是否在內部事務中並且如果是,則禁止它(因為您無論如何不希望您的日志記錄代碼以任何方式影響環境事務):

private static void HandleException(Exception ex) {
    TransactionScope scope = null;
    if (Transaction.Current != null)
        scope = new TransactionScope(TransactionScopeOption.Suppress);
    try {
        // do stuff
    }
    finally {
        scope?.Dispose();
    }
}

或者也許只是總是在被抑制的TransactionScope內部運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM