簡體   English   中英

異步提交或回滾事務范圍

[英]Asynchronously commit or rollback a transaction scope

眾所周知,在 .Net 中引入async await模式時, TransactionScope被遺忘了。 如果我們試圖在事務范圍內使用一些await調用,它們就會被破壞。

現在,由於范圍構造函數選項,此問題已修復。

但在我看來仍然缺少一個部分,至少我無法找到如何以簡單的“類似事務范圍”的方式做到這一點:如何等待范圍的提交或回滾?

提交和回滾也是 IO 操作,它們應該是可等待的。 但由於它們發生在作用域處置上,我們必須等待處置。 如果沒有事務范圍實現IAsyncDisposable ,這是IAsyncDisposable ,目前情況並非如此。

我也查看了System.Transactions.Transaction接口:那里也沒有可等待的方法。

我知道提交和回滾幾乎只是向數據庫發送一個標志,所以它應該很快。 但是對於分布式事務,這可能會不那么快。 無論如何,這仍然是一些阻塞 IO。

關於分布式案例,請記住這可能會觸發兩階段提交。 在某些情況下,在第一階段(准備)會征集額外的持久資源。 這通常意味着針對那些最近登記的資源發出一些額外的查詢。 在提交期間發生的所有事情。

那么有沒有辦法等待事務范圍? 還是System.Transactions.Transaction代替?

注意:我不認為這是“是否可以異步提交/回滾 SqlTransaction? ”的重復。 SqlTransaction比系統事務更受限制。 它們只能尋址 SQL-Server 並且從不分發。 其他一些事務確實有異步方法,例如Npgsql 現在對於事務范圍/系統事務具有異步方法,可能需要DbTransaction具有異步方法。 (我不知道系統事務的內部結構,但它可能正在使用這個 ADO.NET 合同。我們將連接加入系統事務的方式確實讓我認為它並沒有使用它。)
更新: DbTransaction在 .Net Core 3.0 中確實有它們,請參閱#35012 (特別感謝Roji )。

到目前為止還沒有辦法實現它。 他們正在努力

也許是一個遲到的答案,但您想要的基本上歸結為一種可以輕松創建的語法糖。

概括您的問題,我實現了“異步使用”語法,它允許“使用”的主體和“處置”部分都可以等待。 這是它的外觀:

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 ,主體或處置拋出的任何異常都將包裝在AggregateException 當 body 和 dispose 都拋出異常時,這很有用,並且可以在AggregateException檢查這兩個異常。 使用常規using子句,只會捕獲由 dispose 拋出的異常,除非主體顯式包含在try..catch

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM