众所周知,{。1}} TransactionScope
模式在.Net中引入时,async
被遗忘了。如果我们试图在事务范围内使用一些await
调用,它们就会被破坏。
现在由于scope constructor option而修复了这个问题。
但在我看来还有一个缺失的部分,至少我无法在一个简单的交易范围内找到如何做到这一点,比如"方式:如何等待提交或回滚范围?
提交和回滚也是IO操作,它们应该是等待的。但由于它们发生在范围处理上,我们将不得不等待处置。这看起来并不可行(await
模式也不实用)。
我也看了System.Transactions.Transaction
界面:没有等待的方法。
我知道提交和回滚几乎只是向数据库发送一个标志,所以它应该很快。但是对于分布式事务,这可能会更快。无论如何,这仍然是一些阻止IO。
关于分布式案例,请记住这可能会触发两阶段提交。在某些情况下,在第一阶段(准备)期间会招募额外的耐用资源。然后通常意味着针对那些最近登记的资源发布了一些额外的查询。在提交期间发生的所有事情。
有没有办法等待交易范围?或者改为using
?
注意:我不认为这是" Is it possible to commit/rollback SqlTransaction in asynchronous?"的副本。 System.Transactions.Transaction
比系统事务更受限制。它们只能处理SQL-Server,并且永远不会分发。其他一些事务确实有异步方法,例如Npgsql。现在,对于在事务范围/系统事务上使用异步方法,可能需要DbTransaction
来使用异步方法。 (我不知道系统事务的内部,但它可能使用这个ADO.NET契约。我们将连接添加到系统事务中的方式让我觉得它不会使用它。)
答案 0 :(得分:6)
到目前为止,尚无办法实现。但是they work on it
答案 1 :(得分:1)
也许是一个迟到的答案,但你想要的基本上归结为一种可以很容易地自己创造的语法糖。
概括您的问题,我使用"实现了" async;语法,允许身体和" dispose" "使用"的一部分等待。以下是它的外观:
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
子句相比,错误处理存在差异。使用UsingAsync.Do
时,正文或dispose抛出的任何异常都将包含在AggregateException
中。当body和dispose都抛出异常时,这很有用,并且可以在AggregateException
中检查这两个异常。使用常规using
子句,只会捕获dispose抛出的异常,除非正文明确地包含在try..catch
中。