asynchronous提交或回滚事务作用域
众所周知,在.NET中引入async
await
模式时, TransactionScope
被遗忘了。 如果我们试图在事务范围内使用一些await
调用,它们就会被破坏。
现在这是固定的,由于范围构造选项 。
但是在我看来,还有一个缺失的部分,至less我无法find如何在简单的“事务范围”方式中这样做:如何等待范围的提交或回滚?
提交和回滚也是IO操作,它们应该是可以等待的。 但是,由于它们是在处理范围内发生的,我们将不得不等待处置。 这看起来不可行( using
模式也不实际)。
我也看了一下System.Transactions.Transaction
接口:在那里也没有可以使用的方法。
我明白,提交和回滚几乎只是向数据库发送一个标志,所以它应该是快速的。 但是对于分布式交易,这可能不那么快。 无论如何,这仍然是一些封锁IO。
关于分布式病例,请记住这可能会触发两个阶段提交。 在某些情况下,在第一阶段(准备阶段)需要额外的耐用资源。 那通常意味着对最近入伍的资源发出一些额外的查询。 在提交期间发生的所有事情。
那么有什么方法可以等待事务范围吗? 还是一个System.Transactions.Transaction
?
注意:我不认为这是“ asynchronous提交/回滚SqlTransaction? ”的副本。 SqlTransaction
比系统事务更有限。 他们只能解决SQL Server,并且从不分发。 其他一些事务具有asynchronous方法,如Npgsql 。 现在,对于事务范围/系统事务有asynchronous方法, DbTransaction
可能需要有asynchronous方法。 (我不知道系统事务的内部,但也许是使用这个ADO.NET合约,我们把连接join系统事务的方式让我觉得它并没有使用它。
也许是一个迟到的答案,但你想要的东西基本上归结为一种可以容易地创build自己的语法糖。
推广你的问题,我实现了一个“asynchronous使用”的语法,它允许身体和“使用”的“处置”部分都是可以等待的。 以下是它的外观:
async Task DoSomething() { await UsingAsync.Do( // this is the disposable usually passed to using(...) new TransactionScope(TransactionScopeAsyncFlowOption.Enabled), // this is the body of the using() {...} async transaction => { await Task.Delay(100); // do any async stuff here... transaction.Complete(); // mark transaction for Commit } // <-- the "dispose" part is also awaitable ); }
实现如此简单:
public static class UsingAsync { public static async Task Do<TDisposable>( TDisposable disposable, Func<TDisposable, Task> body) where TDisposable : IDisposable { try { await body(disposable); } finally { if (disposable != null) { await Task.Run(() => disposable.Dispose()); } } } }
与常规using
条款相比,error handling有所不同。 使用UsingAsync.Do
,正文或dispose引发的任何exception都将被包装在一个AggregateException
。 当body和dispose都抛出一个exception时,这是非常有用的,这两个exception都可以在AggregateException
检查。 使用常规的using
子句,只有dispose抛出的exception才会被捕获,除非在try..catch
明确地封装了主体。