我目前正在尝试使用嵌套事务范围来访问Azure SQL数据库。
我正在使用以下代码(.Net 4.5.1,我的代码是全异步的,这是带有EF6.1的ASP.Net MVC):
public async Task Test()
{
// In my actual code, the DbContext is injected within the constructor
// of my ASP.Net MVC Controller (thanks to IoC and dependency injection)
// The same DbContext instance is used for the whole HttpRequest
var context = new TestContext();
using (var t1 = StartTransactionForAsync())
{
using (var t2 = StartTransactionForAsync())
{
context.Users.Add(new User { Name = Guid.NewGuid().ToString() });
await context.SaveChangesAsync();
t2.Complete();
}
... // Some more code here
t1.Complete();
}
}
private static TransactionScope StartTransactionForAsync()
{
return new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
TransactionScopeAsyncFlowOption.Enabled);
}
除了有时TransactionScope
会升级到MSDTC(这显然)不受Azure SQL Database支持之外,一切都很好。因此,有时我会遇到以下错误:
已禁用分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问。
我可以在我的连接字符串中添加Enlist=False
,但它会破坏上面的代码,因为即使外部TransactionScope
被处理而没有Complete
,内部事务仍然会插入到数据库中。
我针对一个单独的数据库,在整个HttpRequest
中使用一个单一的Entity Framework上下文,并且始终使用相同的连接字符串。
所以我的问题是:
- Azure SQL Database是否支持嵌套事务?
- 为什么上面的代码有时会升级到MSDTC?
官方文档如下所述:
Microsoft Azure SQL Database不支持分布式事务,即涉及多个资源的事务。有关更多信息,请参阅分布式事务(ADO.NET)。
从版本2.0开始,应用程序事务可以自动升级为分布式事务。这适用于使用System.Data.SqlClient类在System.Transactions事务上下文中执行数据库操作的应用程序。
当您在TransactionScope中打开到不同服务器或数据库的多个连接,或者使用EnlistTransaction方法将多个连接注册到System.Transactions对象时,会发生事务升级。当您同时在同一TransactionScope中或使用EnlistTransaction方法打开到同一服务器和数据库的多个并发连接时,也会发生事务升级。
从版本3.5开始,如果并发连接的连接字符串完全相同,则不会升级事务。有关事务和避免事务升级的更多信息,请参阅System.Transactions与SQL Server(Integration with SQL Server (ADO.NET))。
它没有回答我的任何问题。
TransactionScopeOption.Required
,那么它应该可以工作,尝试查找是否有foreach
语句尝试查询某些内容,我遇到过类似的错误,当我将它们修改为for each (var item in itemQuery.ToList())
而不是 'foreach( var item in itemQuery)' 时,所有这样的嵌套事务错误都消失了。理想情况下,EF 应该检测并给出适当的错误,这是一个误导性的错误。如果仍然存在具有打开阅读器的活动查询,并且在发出 SaveChanges 时,这是 EF 抛出的常见错误。 - Akash Kava