TransactionScope事務處理方法介紹及.NET Core中的註意事項

来源:https://www.cnblogs.com/yilezhu/archive/2018/12/24/10170712.html
-Advertisement-
Play Games

作者:依樂祝 原文鏈接:https://www.cnblogs.com/yilezhu/p/10170712.html 今天在寫CzarCms的UnitOfWork的使用使用到了這個TransactionScope事務,因此對它進行了相關資料的查閱並記錄如下,希望對大伙在.NET Core中使用有所 ...


作者:依樂祝

原文鏈接:https://www.cnblogs.com/yilezhu/p/10170712.html

今天在寫CzarCms的UnitOfWork的使用使用到了這個TransactionScope事務,因此對它進行了相關資料的查閱並記錄如下,希望對大伙在.NET Core中使用有所幫助。

寫在前面

您是否曾嘗試使用C#代碼來實現事務?通常,我們在SQL中一次執行多個Insert / Update語句的話可能就會使用到事務。事務遵循ACID(原子性,一致性,隔離性,持久性)規則,這樣所有的語句要麼全部執行成功要麼全部被取消並執行回滾操作。 而我們今天要講的TransactionScope則可以允許我們在應用程式級別實現這個過程。在某些情況下,您可能需要在同一個資料庫甚至多個資料庫(分散式事務)中執行不同的操作,或者由於某些其他約束,它無法在資料庫級別來完成,或者應用程式的開發人員對資料庫的接觸較少,那麼這時候TransactionScope將會讓你游刃有餘。

什麼是TransactionScope呢?

TransactionScope作為System.Transactions的一部分被引入到.NET 2.0。同時SqlClient for .NET Core 從 2.1 及以上版本開始提供對System.Transactions的支持 。 它是一個類,它提供了一種簡單的方法,可以將一組操作作為事務的一部分來進行處理,而不必擔心場景背後的複雜性。如果某個操作在執行的過程中失敗的話,則整個事務將失敗並執行回滾操作,從而撤消已完成的所有操作。所有這些都將由框架處理,從而確保數據的一致性。

如何使用TransactionScope呢?

要使用它,您需要添加System.Transactions的引用,如果你使用的是.net core的話。這個引用被包含在netcoreapp2.2\System.Transactions.Local.dll 中, 該引用是框架庫的一部分(通常預設情況下不會自動添加)。添加後,在我們想要使用它的地方添加名稱空間 System.Transactions即可。代碼如下所示:

try
{
    using (TransactionScope scope = new TransactionScope())
    {
        // Do Operation 1
        // Do Operation 2
        //...
 
        // 如果所有的操作都執行成功,則Complete()會被調用來提交事務
        // 如果發生異常,則不會調用它並回滾事務
        scope.Complete();
    }
}
catch (ThreadAbortException ex)
{
    // 處理異常
}

在上面的代碼中我們可以看到我們在創建TransactionScope實例時使用了using 語句塊及Disposable塊,它確保了當dispose離開塊並結束事務範圍時調用dispose來進行資源的釋放。
在一個Transaction範圍中,我們可以做多個連接甚至鏈接到不同資料庫的操作的,如下所示:

using (TransactionScope scope = new TransactionScope())
{
    using (con = new SqlConnection(conString1))
    {
        con.Open();
 
        // 執行操作 1
        // 執行操作 2
        //...
    }
 
    using (con = new SqlConnection(conString2))
    {
        con.Open();
 
        // 執行操作 1
        // 執行操作 2
        //...
 
    }
 
    scope.Complete();
}

下麵我們使用兩個不同的資料庫連接字元串來連接不同的資料庫。當然我們也可以根據我們的業務要求使用儘可能多資料庫。我們也可以再事務中嵌套事務。如下代碼所示:

public void DoMultipleTransaction()
{       
    try
    {
        using (TransactionScope scope = new TransactionScope())
        {
            using (con = new SqlConnection(conString1))
            {
                con.Open();
                // 執行操作1
            }
 
            OtherTransaction();
            scope.Complete();
        }
    }
    catch (ThreadAbortException ex)
    {
        // 處理異常
    }
}
 
private void OtherTransaction()
{
    using (TransactionScope scope = new TransactionScope())
    {
        using (con = new SqlConnection(conString2))
        {
            con.Open();
            // 執行操作
        }
        scope.Complete();
    }
}

這裡最頂層的事務範圍稱為根範圍。另外這裡需要註意的是即使通過調用scope.Complete()完成內部事務(上面的OtherTransaction ,如果由於各種原因無法調用rootscope complete,那麼整個事務也將被回滾包括內部的事務。

*註意:執行分散式trsanctions時,您可能會收到以下異常之一*

  1. 伺服器上的MSDTC不可用
  2. 已禁用分散式事務管理器(MSDTC)的網路訪問。

這兩個錯誤都是由於同樣的原因,第一個是在資料庫和應用程式是同一個伺服器時發生的,而在另一個則是服務跟資料庫分別部署在兩台伺服器上。對於同一臺伺服器,請轉到run-> cmd-> services.msc。運行名為Distributed Transaction Coordinator的服務並自動啟動啟動類型,以便在系統重新啟動時再次啟動它。對於2,你可能需要參照這個鏈接的內容進行相應的設置

TransactionScope 類提供了多個重載構造函數,它們接受 TransactionScopeOption 類型的枚舉,而該枚舉定義事務範圍行為。

TransactionScope對象有以下三個選項:

  • Required:聯接環境事務,或者在環境事務不存在的情況下創建新的環境事務。
  • RequiresNew:成為新的根範圍,也就是說,啟動一個新事務並使該事務成為其自己範圍中的新環境事務。
  • Suppress:根本不參與事務。 因此沒有環境事務。

如果用 Required] 實例化範圍並且存在環境事務,則該範圍會聯接該事務。 相反,如果不存在環境事務,該範圍就會創建新的事務併成為根範圍。 這是預設值。 在使用 Required時,無論範圍是根範圍還是僅聯接環境事務,該範圍中的代碼都不需要有不同的行為。 該代碼在這兩種情況下的行為應相同。

如果用 RequiresNew 實例化範圍,則它始終為根範圍。 它會啟動一個新事務,並且其事務成為該範圍中的新環境事務。

如果用 Suppress 實例化範圍,則無論是否存在環境事務,範圍都從不參與事務。 始終使用此值實例化的作用域具有null作為其環境事務。

下麵來讓我們看一組實例代碼:

using (TransactionScope scope = new TransactionScope())
{
    // 聯接環境事務,或者在環境事務不存在的情況下創建新的環境事務。
    using (TransactionScope scope1 = new TransactionScope(TransactionScopeOption.Required))
    {
        // Do Operation
        scope1.Complete();
    }
    //成為新的根範圍,也就是說,啟動一個新事務並使該事務成為其自己範圍中的新環境事務。
    using (TransactionScope scope2 = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        // Do Operation
        scope2.Complete();
    }
    //根本不參與事務。 因此沒有環境事務。
    using (TransactionScope scope3 = new TransactionScope(TransactionScopeOption.Suppress))
    {
        // Do Operation
        scope3.Complete();
    }
 
    scope.Complet

在這裡,我們使用不同的TransactionScopeOptions在父事務下創建了三個事務。預設情況下,範圍是required ,這裡父事務就是採用的這個預設參數進行創建的。它是一個創建新事務的根範圍,並將其標記為環境事務。scope1也是使用required創建的,因為我們已經有了一個環境事務(範圍),所以它加入到父事務中。scope2是使用RequiresNew選項創建的,這意味著它是一個獨立於環境事務處理的新事務。scope3是用suppress創建的選項,這意味著它不參與任何環境事務。無論環境事務是否成功執行,它都會被執行。父(全局)範圍完成後,將提交所有環境事務。

註意點

  1. EF Core 依賴資料庫提供程式以實現對 System.Transactions 的支持。 雖然支持在 .NET Framework 的 ADO.NET 提供程式之間十分常見,但最近才將 API 添加到 .NET Core,因此支持並未得到廣泛應用。 如果提供程式未實現對 System.Transactions 的支持,則可能會完全忽略對這些 API 的調用。 SqlClient for .NET Core 從 2.1 及以上版本開始支持 System.Transactions。如果嘗試在低版本中 如.NET Core 2.0中嘗試使用該功能將引發異常。

  2. 自版本 2.1 起,.NET Core 中的 System.Transactions 實現將不包括對分散式事務的支持,因此不能使用 TransactionScopeCommittableTransaction 來跨多個資源管理器協調事務。主要是不依賴windows中的mstsc功能。

  3. 非同步方法使用時需要註意:

    在下麵的例子中,我們在TransactionScope內部使用await

    using(var scope = new TransactionScope())
    { 
      var groups = await Context.ProductGroups.ToListAsync()。ConfigureAwait(false); 
    }

    看起來沒有問題,但它會拋出一個 System.InvalidOperationException:``A TransactionScope must be disposed on the same thread that it was created.

    原因是預設情況下TransactionScope不會從一個線程切換到另一個線程。為瞭解決這個問題,我們必須使用 TransactionScopeAsyncFlowOption.Enabled

    using(var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    { 
      var groups = await Context.ProductGroups.ToListAsync()。ConfigureAwait(false); 
    }

    現在應該可以了吧?這取決於下麵的情況。

    如果我們使用和不使用TransactionScopeAsyncFlowOption這個選項的時候都使用了相同的資料庫連接,並且第一次執行的時候沒有使用這個選項,那麼我們會得到另一個異常: System.InvalidOperationException:``Connection currently has transaction enlisted. Finish current transaction and retry.

    換句話說,由於第一個訪問的原因,第二個會話將會失敗。如下代碼所示:

    try
    {
      using (var scope = new TransactionScope())
      {
        // We know this one - System.InvalidOperationException: 
        // TransactionScope必須放在與創建它相同的線程上。
        var groups = await Context.ProductGroups.ToListAsync().ConfigureAwait(false);
     }
    }
    catch (Exception e)
    {
      // error handling
    }
    
    using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
      // Implemented correctly but throws anyways
      // System.InvalidOperationException:
      // 當前連接已經被記錄。完成當前事務並重試。
      var groups = await Context.ProductGroups.ToListAsync().ConfigureAwait(false);
    }

    想象一下,如果第一個調用是在第三方庫或您正在使用的框架中完成的,二您不瞭解其中的代碼 - 如果您之前沒有看到此錯誤,那麼你講無從下手來解決這個問題。

    總結

    本文帶著大家熟悉了一遍TransactionScope並對其使用進行了介紹!同時介紹了在.NET Core中使用TransactionScope的一些註意事項!希望對大家有所幫助。另附上.NET Core實戰項目交流群:637326624


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 快速讀入模版 ...
  • 1. 瞭解python2和python3類的區別 python2在2.3之前使用的是經典類, 2.3之後, 使用的是新式類 2. 經典類的MRO 樹形結構的深度優先遍歷 -> 樹形結構遍歷 從左到右,深度遞歸,一直到頭再返回 Foo -> H -> G -> D -> B -> A -> C -> ...
  • super(類名, self) 從某個類開始找下一個MRO 第一步: 先找一下整個程式的MRO 用c3演算法查找: 查找順序如上,知道了執行順序就可以按流程執行了 ...
  • 1、在使用query和update在什麼時候使用帶Connection參數的? 在已經獲取到了DataSource 對象之後,不必使用帶Connection參數的方法 DataSource dataSource = DBCPUtil.getDataSource(); QueryRunner quer ...
  • 【寫在前面】正直青春年少的你,遇到了你的她了嗎?還是你也和我們今天的主人公一樣,在最美好的年級,正在為你的初衷努力著,堅持著,奔波著..... 作者:李偉 我的黑客時代 01 大學專業是電子信息工程,不甚喜歡。我更喜歡在室友上課的時候,獨自一人待在宿舍抓肉雞,併為之廢寢忘食。每天拿著掃描器,導入成千 ...
  • 轉自:https://blog.csdn.net/flyoutsan/article/details/52811095 cmd變數通過set設置變數,通過可以使用set /?查看有關變數的幫助文檔。 接下來談set的用法: 1.set 變數名=值 值可以包含空格、一直到命令結束,也可以是Ctrl+G ...
  • java調用webservice介面方式有多種,本人很懶,測試一種滿足我的需求,故為試驗其他方法,僅供參考 一:工具 MyEclipse,C#編碼發佈的webservice介面 二:步驟 1、打開myeclipse 2、新建一個Web Project 項目 3、引用webservice介面: ①選中 ...
  • @ "TOC" 項目介紹 伏羲之光是一個基於Opencv+GDAL的圖像處理軟體,採用ASP.NET Core 2.1 開發程式,可以生成跨平臺可執行程式。 最初的幻想 我們希望打造一個跨平臺圖片“操作系統”: 1. 純命令行 調用 ,簡單暴力; 2. 使用ASP.NET Core 開發,跨平臺能力 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...