TransactionScope是.net平台基于的分布式事务组件,它默认为本地事务,同时当系统有需要时可以自动提升为分布式事务,而对系统的前提是要开启MSDTC服务,必要时需要在数据库服务器与应用服务器之间添加hosts的映射,这些在之前已经写过很多文章了,在这里不再说了。
之前对TransactionScope的一些理解和总结
第二十六回 将不确定变为确定~transactionscope何时提升为分布式事务?
class="postTitle2">第二十七回 将不确定变为确定~transactionscope何时提升为分布式事务~续
第二十八回 将不确定变为确定~transactionscope何时提升为分布式事务~再续(避免引起不必要的MSDTC)
第三十七回 将不确定变为确定~transactionscope何时提升为分布式事务~SQL2005与SQL2008不同
第三十八回 将不确定变为确定~transactionscope何时提升为分布式事务?(sql2005数据库解决提升到MSDTC的办法)
在efcore平台时,你使用TransactionScope将会出现异常,微软会提示你去查看相关资料,这回资料挺准!https://docs.microsoft.com/en-us/ef/core/saving/transactions
本文章主要说了几点内容
一 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 } } }
有了这种数据上下文事务之后,我们以后在进行efcore开发时就方便多了!
建议:如果这个事务可以脱离数据上下文那就真的解耦了,相当,这种事务的本质也是数据库的事务,所以还真离不开dbContext!
感谢微软这么完整的解释!