2012-03-13 116 views
5

我試圖避免MSDTC在我的應用程序中升級。我在SQL Server Express 2008 R2中使用LINQ,稍後將使用完整版本。導致MSDTC升級的嵌套TransactionScope和/或嵌套連接

我寫了一個數據庫包裝類,它根據需要創建連接並儘快處理它們。連接字符串在所有連接中保持不變。

這裏是我班的一個非常精簡版:

public class SqlServerDatabaseWrapper { 

    public SqlServerDatabaseWrapper(string connectionString) { 
    ConnectionString = connectionString; 
    } 

    public string ConnectionString { get; private set; } 

    private static IDbConnection GetOpenConnection() { 
    var conn = new SqlConnection(ConnectionString); 
    conn.Open(); 
    return conn; 
    } 

    // there is also a second method to return a value 
    // there is PerformCommandAction for SqlCommand as well 
    public void PerformDataContextAction<TContext>(Func<IDbConnection, TContext> creator, Action<TContext> action) where TContext : DataContext { 
    PerformConnectionAction(conn => { 
     using (var context = creator(conn)) 
     action(context); 
    }); 
    } 

    // there is also a second method to return a value 
    public void PerformConnectionAction(Action<IDbConnection> action) { 
    using (IDbConnection conn = GetOpenConnection(ConnectionString)) { 
     action(conn); 
    } 
    } 
} 

使用方法如下:

var db = new SqlServerDatabaseWrapper(connectionString); 
db.PerformDataContextAction(
    conn => new SomeDataContext(conn), 
    context => { /* do something */ } 
); 

如果我把周圍的PerformConnectionAction方法的內容鎖定,所以只有一個可以一次運行,然後一切正常,但有明顯的性能損失。但是,當我刪除它時,它會升級。

使用包裝器的代碼使用的是TransactionScope,並且可以嵌套TransactionScopes和/或調用PerformDataContextAction或PerformConnectionAction(每個都使用相同的連接字符串創建新的連接);在僞代碼(因爲這可能會在不同的類/方法發生):

var db = new SqlServerDatabaseWrapper(connectionString) 
using (TransactionScope tran = new TransactionScope()) { 
    db.PerformDataContextAction( 
    /* ... */, 
    context => { 
     using (TransactionScope tran2 = new TransactionScope()) { 
     db.PerformConnectionAction(conn => { /* some stuff */ }); 
     tran2.Complete(); 
     } 
    } 
    tran.Complete(); 
} 

還要注意有使用的可能發生在不同的點靜態成員的方法。

我還要補充一點,連接字符串如下:

Data Source=.\SQLEXPRESS;Initial Catalog=db1;User Id=test1;Password=test1;MultipleActiveResultSets=true;Enlist=false; 

的問題是,我該如何重構/重寫我的代碼,使我的應用程序可以執行良好,沒有MSDTC,並沒有引入鎖?

感謝

+0

您使用的是哪個版本的SQL Server? – Oded 2012-03-13 13:29:02

+0

SQL Express 2008 R2,稍後將被放到完整版本 – enashnash 2012-03-13 13:30:43

+0

我有點困惑,添加一個鎖可以防止升級,因爲'TransactionScope'是線程綁定的,鎖只會影響線程的相互作用,但不會影響訂單線程內的操作,除非你的線程引入了非確定性行爲,我可以看到鎖是如何改變的。如果您仍然對答案感興趣,請讓我們更多地瞭解線程方面的情況。 – 2013-10-11 09:16:37

回答

1

是否只使用一個連接到事務範圍內的數據庫? 在事務範圍內創建具有相同或不同連接字符串的兩個連接會將事務升級爲分佈式事務。

您可以將連接存儲在線程靜態變量中,並在事務中的所有工作完成時關閉/處理它。然後每個線程都會擁有自己的連接。

向邏輯添加鎖時,您可能不會獲得分佈式事務,因爲每次連接池都會返回相同的連接。