文章出處

回到目錄

TransactionScope是.net平臺基于的分布式事務組件,它默認為本地事務,同時當系統有需要時可以自動提升為分布式事務,而對系統的前提是要開啟MSDTC服務,必要時需要在數據庫服務器與應用服務器之間添加hosts的映射,這些在之前已經寫過很多文章了,在這里不再說了。

之前對TransactionScope的一些理解和總結

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

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

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

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

第三十八回   將不確定變為確定~transactionscope何時提升為分布式事務?(sql2005數據庫解決提升到MSDTC的辦法)

在efcore平臺時,你使用TransactionScope將會出現異常,微軟會提示你去查看相關資料,這回資料挺準!https://docs.microsoft.com/en-us/ef/core/saving/transactions

本文章主要說了幾點內容

  1. 默認的事務-savechanges依舊是一個事務
  2. 單個上下文實現事務
  3. 不同上下文之間實現事務

一 savechanges依舊是一個事務

和之前的ef一樣,在進行saveChanges()操作時,本身就是一個事務塊,而大叔倉儲習慣把每個操作curd都有自己的saveChanges里,而把數據上下文的savechanges對外隱藏,所以如果你要對兩個倉儲進行insert操作時,你需要添加一個外層的事務來保證數據一致性,這時微軟給出了解決方案。

二 單個上下文實現事務

對于一個數據上下文來說,如果你是多個savechanges,那么可以使用context.Database.BeginTransaction()來實現事務。

  using (var context = new BloggingContext())
        {
            using (var transaction = context.Database.BeginTransaction())
            {
                try
                {
                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
                    context.SaveChanges();

                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
                    context.SaveChanges();

                    var blogs = context.Blogs
                        .OrderBy(b => b.Url)
                        .ToList();

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    // when disposed if either commands fails
                    transaction.Commit();
                }
                catch (Exception)
                {
                    // TODO: Handle failure
                }
            }
        }

三 不同上下文之間實現事務

對于前面的TransactionScope來說,如果是不同的數據上下文來說,我們是無法實現事務操作的,有些同學可以能說它應該被提升為分布式的,但對于EF來說,它是不同實現的,但進行efcore時代之后,這個問題得到了解決!

Cross-context transaction (relational databases only)

You can also share a transaction across multiple context instances. This functionality is only available when 
using a relational database provider because it requires the use of DbTransaction and DbConnection,
which are specific to relational databases.

上面說明,可以實現一個跨數據上下文的事務,只關系型數據庫支持!這個功能大叔認為非常必要,但看它下面給出的實例是針對一個數據上下文的,并不多個上下文的交

叉事務,即并不是兩個數據庫之間的事務

       using (var context1 = new BloggingContext(options))
        {
            using (var transaction = context1.Database.BeginTransaction())
            {
                try
                {
                    context1.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
                    context1.SaveChanges();

                    using (var context2 = new BloggingContext(options))
                    {
                        context2.Database.UseTransaction(transaction.GetDbTransaction());

                        var blogs = context2.Blogs
                            .OrderBy(b => b.Url)
                            .ToList();
                    }

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    // when disposed if either commands fails
                    transaction.Commit();
                }
                catch (Exception)
                {
                    // TODO: Handle failure
                }
            }
        }

而如果真正使用多個上下文進行事務的話,同樣會出現問題:

           var options = new DbContextOptionsBuilder<DemoContext>()
                          .UseMySql("Server=localhost;DataBase=test2;UID=root;Password=root;charset=utf8;port=3306;SslMode=None")
                          .Options;
            using (var context = new DemoContext(options))
            {
                using (var transaction = context.Database.BeginTransaction())
                {
                    var user = new UserInfo
                    {
                        AddTime = DateTime.Now,
                        Email = "test@sina.com",
                        UserName = "test"
                    };
                    context.UserInfo.Add(user);
                    context.SaveChanges();
                    using (var context2 = new TaxContext())
                    {
                        context2.Database.UseTransaction(transaction.GetDbTransaction());
                        context2.UserInfo.Add(new UserInfo { AddTime = DateTime.Now, Email = "tax_test", UserName = "tax" });
                        context2.SaveChanges();
                    }
                    transaction.Commit();
                }
            }

出現下面異常:告訴你,你的數據庫連接不是當前的連接

System.InvalidOperationException:“The specified transaction is not associated with the current connection.
Only transactions associated with the current connection may be used.”

不知道什么時候EF可以解決多數據庫事務的問題,當前你可以使用最終一致性的分布式事務來做這事,不過我們還是一起期待中微軟為我們提出更簡單的解決方案,一個事務

是否為分布式的,應該看數據庫所在服務器是否相同,而不是數據庫連接串是否一致!

感謝微軟這么完整的解釋!

 回到目錄


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()