DotNetCore跨平臺~EFCore廢棄(qi)了TransactionScope取而代之(zhi)的Context.Database.BeginTransaction
TransactionScope是.net平臺基于的(de)分(fen)布式(shi)事(shi)務(wu)(wu)組件,它默(mo)認為(wei)本地事(shi)務(wu)(wu),同時(shi)當系(xi)統有需要時(shi)可以自(zi)動提升為(wei)分(fen)布式(shi)事(shi)務(wu)(wu),而(er)對系(xi)統的(de)前提是要開啟MSDTC服(fu)務(wu)(wu),必要時(shi)需要在(zai)數(shu)據(ju)庫服(fu)務(wu)(wu)器與應(ying)用服(fu)務(wu)(wu)器之(zhi)間添(tian)加hosts的(de)映射,這些在(zai)之(zhi)前已經寫過很(hen)多文章了(le),在(zai)這里不再說了(le)。
之(zhi)前對TransactionScope的一些理(li)解和總結
第二十六回 將不確定變為確定~transactionscope何時提升為分布式事務?
第二十七回 將不確定變為確定~transactionscope何時提升為分布式事務~續
第二十八回 將不確定變為確定~transactionscope何時提升為分布式事務~再續(避免引起不必要的MSDTC)
第三十七回 將不確定變為確定~transactionscope何時提升為分布式事務~SQL2005與SQL2008不同
第三十八回 將不確定變為確定~transactionscope何時提升為分布式事務?(sql2005數據庫解決提升到MSDTC的辦法)
在efcore平臺(tai)時,你(ni)使用TransactionScope將會(hui)出(chu)現異常,微軟會(hui)提示你(ni)去查(cha)看相關資(zi)(zi)料,這回資(zi)(zi)料挺(ting)準(zhun)!//docs.microsoft.com/en-us/ef/core/saving/transactions
本文(wen)章主要(yao)說了幾(ji)點內容
- 默認的事務-savechanges依舊是一個事務
- 單個上下文實現事務
- 不同上下文之間實現事務
一 savechanges依(yi)舊是(shi)一個(ge)事務
和之前(qian)的ef一樣,在進行saveChanges()操作(zuo)(zuo)時,本身(shen)就(jiu)是一個事務(wu)塊,而大(da)叔倉儲習慣把每個操作(zuo)(zuo)curd都有自(zi)己(ji)的saveChanges里,而把數據(ju)(ju)上下文的savechanges對外隱藏,所以如(ru)果你(ni)要對兩個倉儲進行insert操作(zuo)(zuo)時,你(ni)需要添加一個外層的事務(wu)來保(bao)證數據(ju)(ju)一致(zhi)性,這時微軟給出了解(jie)決方(fang)案。
二 單個上下文實現事(shi)務
對于一個數據上下文來說,如果你是多個savechanges,那么可以使用context.Database.BeginTransaction()來實現事務。
using (var context = new BloggingContext()) { using (var transaction = context.Database.BeginTransaction()) { try { context.Blogs.Add(new Blog { Url = "//blogs.msdn.com/dotnet" }); context.SaveChanges(); context.Blogs.Add(new Blog { Url = "//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 } } }
三 不(bu)同(tong)上下(xia)文之(zhi)間實現事務
對于前面的(de)(de)(de)TransactionScope來(lai)說(shuo),如果(guo)是不同(tong)的(de)(de)(de)數(shu)據上下文來(lai)說(shuo),我們(men)是無法實現(xian)事務操作的(de)(de)(de),有些同(tong)學可以(yi)能說(shuo)它應(ying)該被(bei)提升為分布(bu)式的(de)(de)(de),但對于EF來(lai)說(shuo),它是不同(tong)實現(xian)的(de)(de)(de),但進行(xing)efcore時代(dai)之(zhi)后,這個問題得到(dao)了解決!
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.
上面說明,可以實現一個跨數據上下文的事務,只關系型數據庫支持!這個功能大叔認為非常必要,但看(kan)它下面給出的(de)實例是針對(dui)一個數據上下文(wen)的(de),并不多個上下文(wen)的(de)交
叉事務,即并不是兩(liang)個數據(ju)庫(ku)之間的事務。
using (var context1 = new BloggingContext(options)) { using (var transaction = context1.Database.BeginTransaction()) { try { context1.Blogs.Add(new Blog { Url = "//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 } } }
而如果(guo)真正使用多(duo)個上下文(wen)進行(xing)事(shi)務的(de)話(hua),同樣會出現問題:
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(); } }
出現下面(mian)異常(chang):告訴你,你的(de)數(shu)據庫(ku)連接不是當前的(de)連接
System.InvalidOperationException:“The specified transaction is not associated with the current connection.
Only transactions associated with the current connection may be used.”
不知(zhi)道什么時候EF可以解(jie)決多數(shu)據庫事(shi)務(wu)的問(wen)題,當前(qian)你(ni)可以使用(yong)最終一(yi)致性的分布(bu)式事(shi)務(wu)來做(zuo)這事(shi),不過(guo)我們還是一(yi)起期待中微軟為我們提出更簡單的解(jie)決方(fang)案,一(yi)個事(shi)務(wu)
是(shi)(shi)否(fou)為(wei)分布式的,應該看數據庫所在服(fu)務器是(shi)(shi)否(fou)相同,而不是(shi)(shi)數據庫連接串(chuan)是(shi)(shi)否(fou)一致!
感謝微軟這么(me)完整的解釋(shi)!