天天看點

将不确定變為确定~transactionscope何時提升為分布式事務?(sql2005資料庫解決提升到MSDTC的辦法)

回到目錄

對于transactionscope不了解的同學,可以看我的相關文章

第二十六回   将不确定變為确定~transactionscope何時提升為分布式事務?

第二十七回   将不确定變為确定~transactionscope何時提升為分布式事務~續

第二十八回   将不确定變為确定~transactionscope何時提升為分布式事務~再續(避免引起不必要的MSDTC)

第二十九回   将不确定變為确定~transactionscope何時提升為分布式事務~大結局

第三十七回   将不确定變為确定~transactionscope何時提升為分布式事務~SQL2005與SQL2008不同

聲明:

對于這種事務,如果希望程式出錯自動復原,必須将異常throw出來,不能愉愉的用日志記錄!

測試:

對于sql2008已經很好的支援了transactionscope,而對于sql2005來說,支援的不是很好,它将多個savechanges()方法提升為分布式事務msdtc,它不管你是否為一個資料庫,真是無奈了!還好,最好找到了解決方法,下面圖所示,将多個insert,update包裹到一個transactionscope裡,所産生的結果如下:

簡單來說,就是sp_reset_connection重新使用一次SQL連結時,你的事務裡的代碼是被包裹在一起發送過來的,這時,如果有一條SQL語句出現異常,整個包會發生callback!

上面圖中,隻要有一條語句出現SQL異常,都會發生復原,進而保證了資料的完整性。

當然,我們的計算機中,并沒有開啟msdtc服務,有圖有真像

前提:Db資料上下文對象必須與action指向的方法體裡的上下文是同一個。

相關原始代碼為:

var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)Db).ObjectContext;
            try
            {
                objectContext.Connection.Open();
                using (TransactionScope trans = new TransactionScope())
                {
                insert1();
                insert2();
                }
            }
            catch (Exception)
            {

                throw;
            }
            finally
            {
                objectContext.Connection.Close();
            }      

OK,我們将上面代碼進行一個封裝,讓它通路起來更友善一些,看代碼:

/// <summary>
    /// Author:zhang.zhanling
    /// 對TransactionScope,讓它對同一個資料庫不産生msdtc服務
    /// </summary>
    public class TransactionScopeNoMsdtc
    {
        /// <summary>
        /// 産生包裹事務
        /// </summary>
        /// <param name="db">資料上下文</param>
        /// <param name="isOutermost">是否為最外層,預設為false</param>
        /// <param name="action">處理代碼塊</param>
        public static void UsingNoMsdtc(DbContext db, bool isOutermost, Action action)
        {
            var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)db).ObjectContext;
            try
            {
                if (objectContext.Connection.State == System.Data.ConnectionState.Closed)
                    objectContext.Connection.Open();
                using (TransactionScope trans = new TransactionScope())
                {
                    action();
                    trans.Complete();
                }
            }
            finally
            {
                if (isOutermost)//如果是最外層事務,而将連接配接關閉
                    objectContext.Connection.Close();
            }
        }
        /// <summary>
        /// 産生包裹事務,它不是最外層的,如果是最外層的需要調用其它重載
        /// </summary>
        /// <param name="db"></param>
        /// <param name="action"></param>
        public static void UsingNoMsdtc(DbContext db, Action action)
        {
            UsingNoMsdtc(db, false, action);
        }
    }      

在使用時,我們可以這樣來做,不用TransactionScope,而是用TransactionScopeNoMsdtc呵呵。

EntityFrameworks.Data.Core.TransactionScopeNoMsdtc.UsingNoMsdtc(Db, () =>
            {
            insert1();
            insert2();
            });      

感謝閱讀!

作者:倉儲大叔,張占嶺,

榮譽:微軟MVP

QQ:853066980

支付寶掃一掃,為大叔打賞!

将不确定變為确定~transactionscope何時提升為分布式事務?(sql2005資料庫解決提升到MSDTC的辦法)