【发布时间】:2015-08-13 15:39:17
【问题描述】:
我目前正在尝试使用嵌套事务范围对 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 数据库支持。所以我有时会收到以下错误:
分布式事务管理器 (MSDTC) 的网络访问权限已 禁用。请在安全中启用 DTC 以进行网络访问 使用组件服务管理配置 MSDTC 工具。
我可以将Enlist=False 添加到我的连接字符串中,但这会破坏上面的代码,因为即使外部TransactionScope 在没有Complete 的情况下被处置,内部事务仍会插入到数据库中。
我的目标是一个单个数据库,对我的整个HttpRequest 使用单个实体框架上下文,始终使用相同的连接字符串.
所以我的问题是:
- Azure SQL 数据库是否完全支持嵌套事务?
- 为什么上述代码有时会升级到 MSDTC?
Microsoft Azure SQL 数据库不支持分布式 事务,即影响多个资源的事务。 有关详细信息,请参阅分布式事务 (ADO.NET)。
从 2.0 版本开始,应用程序事务可能是 自动提升为分布式事务。这适用于 使用 System.Data.SqlClient 类执行的应用程序 System.Transactions 上下文中的数据库操作 交易。
当您打开多个连接到 TransactionScope 中的不同服务器或数据库,或者当您 通过使用在 System.Transactions 对象中登记多个连接 EnlistTransaction 方法。交易促进也发生在 您打开到同一服务器的多个并发连接,并且 数据库在同一 TransactionScope 内或使用 EnlistTransaction 方法。
从 3.5 版本开始,交易将不会被提升,如果 并发连接的连接字符串正是 相同的。有关交易和避免交易的更多信息 推广,请参阅 System.Transactions 与 SQL Server 的集成 (ADO.NET)。
它没有回答我的任何问题。
【问题讨论】:
-
TransactionScope 是为 implicit/automatic 事务(利用 MSDTC 服务)而不是 nested 事务而发明的。您似乎混淆了这些术语。升级到 DTC 可能正在发生,因为您有一些异步的东西(这意味着不同的线程,这可能意味着不同的连接)。我几乎看不出你为什么要把异步的东西放在这种(服务器?)代码中——超出了当前围绕“异步”的时尚:-)。更多关于升级的信息:stackoverflow.com/questions/1690892/…
-
@SimonMourier 我不确定我是否理解你的第一句话;
TransactionScope绝对支持嵌套事务(参见例如 stackoverflow.com/a/2742025/870604)。回滚根范围应该回滚整个操作。至于异步的东西,我使用它是出于可伸缩性/性能的原因。也就是说,即使这两个操作在两个不同的线程上执行,它们仍然使用相同的 DB 连接(使用了唯一的 DbContext 实例),这并没有改变这一事实。 -
我从未说过 TS 不支持嵌套事务。我说你混淆了这两个概念。嵌套事务早在 DTC 存在之前就已经存在。您可以在没有 TS 的情况下进行嵌套事务,但您说的是嵌套 作用域。异步不会在这里带来任何可扩展性的好处,如果在幕后,您正在对一个独特的连接进行序列化(实际上可能更糟),无论如何我仍然对此表示怀疑。恕我直言,您应该显示完整的重现代码以避免疯狂猜测。
-
分布式事务!=嵌套事务,首先你为什么需要它?如果嵌套事务已经在事务中,可以继续在同一个事务中操作。您可以轻松更改业务逻辑以加入现有事务而不是创建新事务,这就是环境事务的概念。
-
我在打开阅读器并创建新的事务范围时看到此错误,如果您使用 .ToListAsync() 获取所有记录而不是枚举查询,此错误将消失。跨度>
标签: c# azure transactions async-await msdtc