在webapi+ef+sqlserver开发项目时,利用transcope实现应用层级的事务时,偶尔会报分布式事务错误,而且很而复现,特别蛋疼。现将自己的解决方法初步整理下。
分析原因:搭建repository+ef框架时,在repository crud中写了savechange,savechange自身包含事务功能。而代码中又用transcope里面嵌套几个使用repository方法的service时,会报分布式事务错误,我怀疑是事务嵌套引发的。
The underlying provider failed on EnlistTransaction.(ㄒoㄒ) 在 System.Data.Entity.Core.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction) 在 System.Data.Entity.Core.Objects.ObjectContext.EnsureContextIsEnlistedInCurrentTransaction[T](Transaction currentTransaction, Func`1 openConnection, T defaultValue) 在 System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions) 在 System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) 在 System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5() 在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation) 在 System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) 在 System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0() 在 System.Data.Entity.Internal.LazyEnumerator`1.MoveNext() 在 System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
参照stackoverflow https://stackoverflow.com/questions/16020270/the-underlying-provider-failed-on-enlisttransaction-cannot-access-a-disposed-ob
Also - is it possible you have got nested transaction scopes, and some inner scope is being rolled back (disposed without calling complete)
for some reason? Due to how transaction scopes work, that would immediately doom the outer transaction(s), rolling them back immediately. – Marc Gravell
解决方法一:调整代码架构,剔除transcope,在unitofwork中统一savechange,一次提交事务(需要保证一次请求中的service中使用的DbContext为一个,用autofac依赖注入即可实现)。而不是在repository中savechange.
解决方法二:将数据库服务器设置成支持分布式事务。(暂时不推荐,有些情况不是真正的分布式事务,是自个框架、代码问题)
https://bbs.csdn.net/topics/390682626/
# 在两台机器上开启MSDTC【管理工具---组件服务---我的电脑“属性”---MSDTC】
# 开启SQL SERVER的分布式事务支持【属性---连接----最下面的复选框】
#服务中的:Distributed Transaction Coordinator 设置自动开启
#服务中的数据库代理服务:SQL Server Agent (MSSQLSERVER) 设置自动开启
# 确保两台机器的135端口都开着【注意防火墙】
# 确保主机名可以PING通,并且对应的IP是正确的【PING得通,但IP不正确则配置一下host文
件】
#确保SQL SERVER 代理服务开启
#确定在进程中可以看到msdtc.exe进程如果看不到请在CMD下运行"net start msdtc"开启服务
后正常