Dot-Net

C# 中的事務中的事務

  • May 8, 2010

我正在使用 C# 將發票的平面文件導入數據庫。如果遇到問題,我正在使用 TransactionScope 回滾整個操作。

這是一個棘手的輸入文件,因為一行不一定等於一條記錄。它還包括連結的記錄。發票將具有標題行、行項目,然後是總計行。有些發票需要被跳過,但我可能不知道它需要被跳過,直到我到達總行。

一種策略是將標題、行項目和總行儲存在記憶體中,並在達到總行後保存所有內容。我現在正在追求。

但是,我想知道是否可以以不同的方式完成。在發票周圍創建一個“嵌套”交易,插入標題行和行項目,然後在達到總行時更新發票。如果確定需要跳過發票,則此“嵌套”事務將回滾,但整體事務將繼續。

這是可能的,實用的,你將如何設置它?

這是通過事務保存點完成的。它通常看起來像這樣:

BEGIN TRANSACTION
for each invoice
  SAVE TRANSACTION InvoiceStarted
  BEGIN TRY
    Save header
    Save line 1
    Save line 2
    Save Total
  END TRY
  BEGIN CATCH
    ROLLBACK TO Invoicestarted 
    Log Failed Invoice
  END CATCH
end for
COMMIT

我使用了基於 Transact-SQL 的虛擬碼,這絕非偶然。保存點是一個數據庫概念,.Net Transactions 不支持它們。您可以直接使用 SqlTransaction 並利用SqlTransaction.Save,也可以使用仿照異常安全模板建模的 T-SQL 儲存過程。在這種情況下,我建議您避免使用 .Net 事務(即 TransactionScope)。

SQL Server 和 SQL Server都不TransactionScope支持嵌套事務。

您可以嵌套TransactionScope實例,但這只是嵌套事務的外觀。實際上,有一種叫做“環境”事務的東西,一次只能有一個。哪個事務是環境事務取決於您TransactionScopeOption在創建範圍時使用的內容。

為了更詳細地解釋,請考慮以下內容:

using (var outer = new TransactionScope())
{
   DoOuterWork();

   using (var inner1 = new TransactionScope(TransactionScopeOption.Suppress))
   {
       DoWork1();
       inner1.Complete();
   }

   using (var inner2 = new TransactionScope(TransactionScopeOption.RequiresNew))
   {
       DoWork2();
       inner2.Complete();
   }

   using (var inner3 = new TransactionScope(TransactionScopeOption.Required))
   {
       DoWork3();
       inner3.Complete();
   }

   outer.Complete();
}

以下是每個內部作用域發生的情況:

  • inner1在隱式事務中執行,獨立於outer. 發生的任何事情DoWork1都不能保證是原子的。如果這在中途失敗,您將獲得不一致的數據。無論outer.
  • inner2在新事務中執行,獨立於outer. 這是一個不同的事務,outer但它不是嵌套的。如果失敗,在outer( DoOuterWork()) 和任何其他作用域中發生的工作仍然可以送出,但問題是:如果它完成,則回滾整個outer事務不會回滾內部完成的工作inner2 這就是它不是真正嵌套的原因。此外,inner2將無法訪問任何由 鎖定的行outer,因此如果您不小心,您可能會在這裡遇到死鎖。
  • inner3在與相同的事務中執行outer。這是預設行為。如果DoWork3()失敗並且inner3永遠不會完成,則整個outer事務將回滾。類似地,如果inner3成功完成但outer被回滾,那麼在其中完成的任何工作DoWork3()也會被回滾。

因此,您可以希望看到這些選項實際上都不是嵌套的,並且不會給您想要的。該Required選項近似於嵌套事務,但不能讓您獨立送出或回滾事務內的特定工作單元。

在 SQL Server 中,最接近真正嵌套事務的是SAVE TRAN語句與一些TRY/CATCH塊的組合。如果您可以將邏輯放在一個或多個儲存過程中,這將是一個不錯的選擇。

否則,您需要按照 Oded 的建議為每張發票使用單獨的交易。

引用自:https://stackoverflow.com/questions/2794761