回到目錄 TransactionScope是.net平臺基於的分散式事務組件,它預設為本地事務,同時當系統有需要時可以自動提升為分散式事務,而對系統的前提是要開啟MSDTC服務,必要時需要在資料庫伺服器與應用伺服器之間添加hosts的映射,這些在之前已經寫過很多文章了,在這裡不再說了。 之前對Tra ...
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
本文章主要說了幾點內容
- 預設的事務-savechanges依舊是一個事務
- 單個上下文實現事務
- 不同上下文之間實現事務
一 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 = "[email protected]", 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可以解決多資料庫事務的問題,當前你可以使用最終一致性的分散式事務來做這事,不過我們還是一起期待中微軟為我們提出更簡單的解決方案,一個事務
是否為分散式的,應該看資料庫所在伺服器是否相同,而不是資料庫連接串是否一致!
感謝微軟這麼完整的解釋!