<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      WizardWu 編程網(wǎng)

      一位臺灣的工程師,接觸 .NET 逾十年,近年研究 SQL Server、Performance Tuning、手機應(yīng)用

      博客園 首頁 新隨筆 聯(lián)系 訂閱 管理

      做項目或系統(tǒng)設(shè)計時,依需求的不同,適必有不同的解決方案,有的以性能為主,有的以可擴展性為主,有的為了日后易于維護而做大量的組件化。本帖依此提供三種不同特性的「事務(wù)」ASP.NET 示例下載,包括:用一個數(shù)據(jù)庫 Connection 即可高性能跨數(shù)據(jù)庫寫入、透過組件的函數(shù)調(diào)用即可參與事務(wù)、異步 (Asynchronous) 執(zhí)行事務(wù)。

       

      三個 ASP.NET 示例,其「事務(wù)」特性分別為:

      (1) 兼顧性能與功能 - 利用 SqlConnection 類的 ChangeDatabase 方法,在單一個 Connection 中,跨越本機的兩個數(shù)據(jù)庫做 LTE (輕量級) 事務(wù)。
      (2) 追求良好的架構(gòu)、組件化及可維護性 - 利用 TransactionScope 類 + MS DTC,直接經(jīng)由各組件之間的函數(shù)調(diào)用,將其納入同一個事務(wù),亦可升級為 OleTx 分布式事務(wù)。
      (3) 重視回應(yīng)速度與用戶體驗 - 利用 CommittableTransaction + AsyncCallback 類,進行明確式的「異步 (Asynchronous)」事務(wù)。

       

      -------------------------------------------------
      本帖的示例下載點:
      https://files.cnblogs.com/WizardWu/100204.zip
      (執(zhí)行第一個示例,需要 SQL Server 的 Northwind、AdventureWorksDW 數(shù)據(jù)庫,不需要 DTC)
      (執(zhí)行第二個示例,需要 SQL Server 的 Northwind 數(shù)據(jù)庫,并事先設(shè)置好 Windows 上的 DTC 分布式事務(wù)處理協(xié)調(diào)器)
      (執(zhí)行第三個示例,需要 SQL Server 的 Northwind 數(shù)據(jù)庫,不需要 DTC)
      ---------------------------------------------------

       

      (一) 示例一:兼顧性能與功能

        

      有時我們只是臨時需要在某一臺機器上的 SQL Server,跨越其中的兩個數(shù)據(jù)庫做事務(wù)處理,或是其他一些簡易的本機事務(wù)處理,此時只要透過一些 ADO.NET 的小技巧,利用同一個 Connection 對象,和最傳統(tǒng)的 SqlTransaction 即可辦到。如下方代碼,透過 SqlConnection 的 ChangeDatabase 方法,即可在 Northwind、AdventureWorksDW 兩個數(shù)據(jù)庫之間切換,無須大費周章地升級為分布式事務(wù),或浪費資源創(chuàng)建兩次數(shù)據(jù)庫的 Connection。

       

      示例一
      protected void Button1_Click(object sender, EventArgs e)
      {
      SqlConnection cn
      = new SqlConnection("server=localhost;database=Northwind;integrated security=true");
      SqlTransaction tx
      = null;
      try
      {
      cn.Open();
      tx
      = cn.BeginTransaction();
      SqlCommand cmd1
      = new SqlCommand("INSERT INTO Employees (LastName, FirstName) VALUES('Wu', 'Wizard')", cn);
      cmd1.Transaction
      = tx;
      cmd1.ExecuteNonQuery();


      cn.ChangeDatabase("AdventureWorksDW");


      SqlCommand cmd2
      = new SqlCommand("INSERT INTO DimGeography (City) VALUES ('Taipei')", cn);

      cmd2.Transaction
      = tx;

      cmd2.ExecuteNonQuery();
      tx.Commit();
      Response.Write(
      "跨越兩個數(shù)據(jù)庫的 LTE 本機事務(wù)成功 !");
      }
      catch (SqlException ex)
      {
      tx.Rollback();
      Response.Write(
      "發(fā)生錯誤: " + ex.Message);
      }
      finally
      {
      cn.Close();
      cn.Dispose();
      }
      }

       

       市面上有好幾本專講 ADO.NET 的中、英文書籍,內(nèi)容都相當不錯,只可惜這方面的議題較少受到重視。

       

      ----------------------------------------------------------------------------

       

      (二) 示例二:追求良好的架構(gòu)、組件化及可維護性

       

      有些寫 Java 或比較重視架構(gòu)設(shè)計的工程師,常會將一些特定的功能或商業(yè)邏輯,各自封裝在多個組件或類之中 (Java 中的 Bean 或 SessionBean)。微軟方面,自從 .NET 2.0 問世、TransactonScope 類和新世代的事務(wù)管理機制出現(xiàn)后,以往用 COM+ 的寫法才能達到的功能,現(xiàn)在用 TransactonScope 類竟然很輕松地就能達成,這讓 OOA/OOD、面向?qū)ο蠛?Design Patterns 的愛好者,在 .NET 平臺上有了很好的解套方式。亦即可讓對象的行為,在架構(gòu)設(shè)計上能夠獨立,但卻能隨時決定是否要參與某個事務(wù),或動態(tài)地決定是否要從 Local 事務(wù)升級成分布式事務(wù)。

      例如下方的代碼,為兩個類 (或組件) 里各自的函數(shù),他們可能是 ERP 中的「訂單產(chǎn)生」組件,要調(diào)用「倉庫對象」組件,去扣除一些庫存量。透過「巢狀 (nested);嵌套」的二或多個  TransactonScope 類,以及函數(shù)的直接調(diào)用,即可將對方納入此一事務(wù),并可自定義是否要納入成為同一個事務(wù),并且升級成分布式事務(wù)、啟動 DTC,抑或拆分成兩個事務(wù)、不啟動 DTC。且不論是哪種選項,都能達到任一方拋出 Exception 時,雙方都能自動 Rollback。

       

      Class1
      {
      private void func1()
      {
      using (TransactionScope scope = new TransactionScope())
      {
      Class2 c2
      = new Class2();
      c2.func2();
      //調(diào)用另一個組件的函數(shù),直接將它納入事務(wù)
                  scope.Complete();
      }
      }
      }


      Class2

      {
      public void func2()
      {
      using (TransactionScope scope = new TransactionScope())
      {
      scope.Complete();
      }
      }
      }

       

       

      下圖 1 為本帖下載示例 - 示例二的執(zhí)行畫面。如前述,我們用兩個 Class 中函數(shù)調(diào)用的做法,但 Class 1、Class 2 的 TransactionScope,其 TransactionScopeOption 都設(shè)置為 Required (若已有現(xiàn)存的事務(wù),則參與該個事務(wù)),表示雙方要加入「同一個」事務(wù)中。因此 Class 1 所插入數(shù)據(jù)庫的一條記錄,Class 2 立即可 SELECT 得到它,因為他們是在「同一個」事務(wù)中。但代價是會啟動 MS DTC、自動升級成 OleTx 分布式事務(wù)。雖然這兩個 Class 是在同一臺機器中,但因為在同一個事務(wù)中,開啟了兩條數(shù)據(jù)庫的 Connection,因此仍會自動從本機的輕量級 LTM 事務(wù)管理員,升級成 OleTx 事務(wù)管理員 (依賴 RPC 遠端程序調(diào)用),也因此會自動啟用 MS DTC (若 DTC 已設(shè)置好)。

      但若您把 Class 2 的 TransactionScope,其 TransactionScopeOption 設(shè)置為 RequiresNew (不管是否有現(xiàn)存事務(wù),都一律創(chuàng)建新的事務(wù)),您會發(fā)現(xiàn) MS DTC 不會啟動了,因為他們已被拆分成「二個事務(wù)」,也因此 Class 1 所插入數(shù)據(jù)庫的一條記錄,Class 2 已無法立即 SELECT 取得,因為他們不在「同一個」事務(wù)中。

       

      但不論是前述哪種做法,仍都能達到任一方引發(fā) Exception 時,雙方都能自動 Rollback。若您以前,曾經(jīng)夢想透過 Web Service 彼此的調(diào)用,來達到事務(wù)的完整性,會發(fā)現(xiàn)情形如同前述的第二種,亦即被拆分成「二個事務(wù)」,雖然任一方拋出 Exception 時,雙方都能自動 Rollback,但由于是拆分成二個事務(wù),因此第一個 Web Service 所插入數(shù)據(jù)庫的一條記錄,第二個 Web Service 無法立即取得。而這點,就某些系統(tǒng)的設(shè)計需求上,雖然看似小瑕疵,卻是不被允許的。可能有些人寧愿用第一種做法,包成「同一個」事務(wù),寧可啟動 MS DTC,犧牲一些性能,也要達成事務(wù)的高度完整性。

       


      圖 1 示例二的執(zhí)行畫面

       

      示例二的 Class1 (組件一)
      using System;
      using System.Data;

      using System.Transactions;
      using System.Data.SqlClient;

      public class Class1
      {
      private string strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["Conn_Northwind"].ToString();

      public Class1()
      {
      }

      public string func1()
      {
      SqlConnection conn
      = null;
      SqlCommand cmd
      = null;
      int intTheNewestID = 0;
      string strReturn = "";

      //Insert 后,立即 Select 出數(shù)據(jù)庫最新插入的這一筆記錄,其 id 值 (identity, 由數(shù)據(jù)庫自動增號)
      string strSql = "INSERT INTO Employees (LastName, FirstName) VALUES('Wu', 'Wizard') ; SELECT @@identity; ";

      //Required 選項: 當前環(huán)境若無事務(wù),則創(chuàng)建新事務(wù),否則就加入當前環(huán)境的同一個事務(wù)
      using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
      {
      try
      {
      conn
      = new SqlConnection(strConnString);
      conn.Open();
      if (conn.State == ConnectionState.Open)
      {
      cmd
      = new SqlCommand(strSql, conn);
      intTheNewestID
      = Convert.ToInt32(cmd.ExecuteScalar());

      //調(diào)用 Class 2 的函數(shù),將其也加入同一個事務(wù)
      Class2 c2 = new Class2();
      strReturn
      = c2.func2(intTheNewestID);

      scope.Complete();
      }
      }
      catch (Exception ex)
      {
      throw new Exception("組件一 - 發(fā)生數(shù)據(jù)庫訪問錯誤: " + ex.ToString());
      }
      finally
      {
      if (cmd != null)
      cmd.Dispose();
      if (conn.State == ConnectionState.Open)
      {
      conn.Close();
      }
      conn.Dispose();
      }
      }

      return strReturn; //返回前臺的網(wǎng)頁中顯示
      }
      }

       

       

      示例二的 Class2 (組件二)
      using System;
      using System.Data;

      using System.Transactions;
      using System.Data.SqlClient;

      public class Class2
      {
      private string strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["Conn_Northwind"].ToString();

      public Class2()
      {
      }

      public string func2(int intTheNewestID)
      {
      SqlConnection conn
      = null;
      SqlCommand cmd1
      = null;
      SqlCommand cmd2
      = null;
      int intInserted = 0;
      string strReturn = "";
      string strSql1 = "INSERT INTO Employees (LastName, FirstName) VALUES('Lee', 'David')";
      string strSql2 = "SELECT LastName FROM Employees WHERE EmployeeID=" + intTheNewestID;

      //Required 選項: 當前環(huán)境若無事務(wù),則創(chuàng)建新事務(wù),否則就加入當前環(huán)境的同一個事務(wù)。在此例中,會啟動 DTC,第二句 Select 會成功。
      //RequiresNew 選項: 總是創(chuàng)建新的事務(wù),會造成 Class1、Class2 不會處于同一個事務(wù)里。在此例中,不會啟動 DTC,第二句 Select 會失敗。
      //Suppress 選項: 不加入此一事務(wù)。
      using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
      {
      try
      {
      conn
      = new SqlConnection(strConnString);
      conn.Open();
      if (conn.State == ConnectionState.Open)
      {
      cmd1
      = new SqlCommand(strSql1, conn);
      intInserted
      = cmd1.ExecuteNonQuery();

      //取得組件一里,剛剛才插入的那一筆記錄,以確認組件一、組件二確實是在同一個事務(wù)中執(zhí)行,而不是拆分成兩個事務(wù)
      cmd2 = new SqlCommand(strSql2, conn);
      strReturn
      = cmd2.ExecuteScalar().ToString();

      scope.Complete();
      }
      }
      catch (Exception ex)
      {
      throw new Exception("組件二 - 數(shù)據(jù)庫訪問發(fā)生錯誤: " + ex.ToString());
      }
      finally
      {
      if (cmd1 != null)
      cmd1.Dispose();
      if (cmd2 != null)
      cmd2.Dispose();
      if (conn.State == ConnectionState.Open)
      {
      conn.Close();
      }
      conn.Dispose();
      }
      }

      return strReturn; //返回組件一
      }
      }

       

       

      MSDN 上有一篇文章 [1],或一些 ADO.NET 書籍,有介紹此種 Nested TransactionScope,及其 TransactionScopeOption 的設(shè)置。如下圖 2,最左側(cè)為沒有事務(wù)的代碼,當其調(diào)用了 scope1 時 (Required),創(chuàng)建了全新的事務(wù) Transaction A。接下來,當創(chuàng)建了第二個 scope2,或如本帖示例二調(diào)用了第二個組件時,由于也是 Reuqired,因此和本帖示例二的情況一模一樣,雙方會包在「同一個」事務(wù) A 中,并可能會啟動 MS DTC。

      當創(chuàng)建了第三個 scope3,或呼叫了第三個組件時,由于是 ReuqiresNew,因此會創(chuàng)建「另一個」事務(wù) Transaction B。而當創(chuàng)建了第四個 scope4,或調(diào)用了第四個組件時,因設(shè)置為 Suppress (表示無論如何不加入事務(wù)),因此其會獨立執(zhí)行,不參與任何事務(wù)。此種 Supppress 設(shè)置,適用于調(diào)用第三方廠商或協(xié)力廠商的組件,或是單純執(zhí)行 SELECT 語句,不需要或不想加入事務(wù)時的情形。

       

      //Default TransactionScopeOption is "Required"
      using(TransactionScope scope1 = new TransactionScope())
      {
      using(TransactionScope scope2 = new TransactionScope(TransactionScopeOption.Required))
      {...}

      using(TransactionScope scope3 = new TransactionScope(TransactionScopeOption.RequiresNew))
      {...}

      using(TransactionScope scope4 = new TransactionScope(TransactionScopeOption.Suppress))
      {...}

      //...
      }

       

       

      圖 2 不同 TransactionScopeOption 設(shè)置的執(zhí)行結(jié)果


      在我先前寫過的文章「網(wǎng)站性能優(yōu)化 - 數(shù)據(jù)庫及服務(wù)器架構(gòu)篇」,里面的圖 3 -「物理」上的分層,各種商業(yè)邏輯可能存在多臺物理主機上,里面有提到,這些不同功能的組件或商業(yè)邏輯,可能在同一臺 AP Server  上,也可能分布在不同的服務(wù)器上。因此要以哪種方式來調(diào)用,或同一臺機器上的組件,是否有必要犧牲一些性能、啟用 DTC 來運作,以達成特定需求的系統(tǒng)設(shè)計,應(yīng)事先做好評估。

       

      ----------------------------------------------------------------------------

       

      (三) 示例三:重視回應(yīng)速度與用戶體驗

       

      若事務(wù)訪問了多個數(shù)據(jù)庫,或因網(wǎng)絡(luò)太慢,讓事務(wù)時間拉太長,我們還可考慮用 CommittableTransaction 類,以「異步 (Asynchronous)」方式來處理事務(wù)。其原理為利用另一條背景線程,來等待事務(wù)處理的結(jié)果,讓主程序 (客戶端的瀏覽器) 能先進行其他的操作,避免讓用戶處于等待的情況。

      如下方示例三的部分代碼,執(zhí)行異步事務(wù)時,需提供一個 Callback 方法,在 Commit 時自動調(diào)用,亦即下方示例的 OnCommitted 方法。當執(zhí)行到這個方法時,便會從 Thread Pool 里取得一條線程,進行異步的事務(wù)確認。

       

      示例三
      using System;

      using System.Data;
      using System.Transactions;
      using System.Data.SqlClient;

      public partial class _Default : System.Web.UI.Page
      {
      private string strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["Conn_Northwind"].ToString();

      protected void Page_Load(object sender, EventArgs e)
      {
      }

      protected void Button1_Click(object sender, EventArgs e)
      {
      SqlConnection conn
      = null;
      SqlCommand cmd
      = null;

      string strSql = "INSERT INTO Employees (LastName, FirstName) VALUES('Wu', 'Wizard')";

      //用 CommittableTransaction 進行明確式事務(wù)
      using (CommittableTransaction tran = new CommittableTransaction())
      {
      try
      {
      conn
      = new SqlConnection(strConnString);
      conn.Open();
      conn.EnlistTransaction(tran);
      if (conn.State == ConnectionState.Open)
      {
      cmd
      = new SqlCommand(strSql, conn);
      cmd.ExecuteNonQuery();

      //指定 Callback 函數(shù)為 OnCommitted
      AsyncCallback ac = new AsyncCallback(OnCommitted);
      tran.BeginCommit(ac,
      null); //開始一個異步事務(wù)

      //tran.Commit(); //同步事務(wù)的寫法
      }
      }
      catch (Exception ex)
      {
      tran.Rollback();
      Response.Write(
      "程序發(fā)生錯誤: " + ex.Message);
      }
      finally
      {
      if (cmd != null)
      cmd.Dispose();
      if (conn.State == ConnectionState.Open)
      {
      conn.Close();
      }
      conn.Dispose();
      }
      }
      }

      //執(zhí)行到這個方法時,會從 Thread Pool 里取得一條線程,進行異步的事務(wù)
      private void OnCommitted(IAsyncResult ar) //傳入一個 IAsyncResult 參數(shù)
      {
      CommittableTransaction Tx;
      Tx
      = (CommittableTransaction)ar;

      try
      {
      using ((Tx))
      {
      Tx.EndCommit(ar);
      //結(jié)束異步事務(wù)
      }

      Response.Write(
      "異步事務(wù)完成,已成功插入一條記錄。");
      }
      catch (TransactionException ex)
      {
      Tx.Rollback();
      Response.Write(
      "異步事務(wù)失敗,錯誤信息為:" + ex.Message);
      }
      finally
      {
      if (Tx != null)
      Tx.Dispose();
      }
      }

      }

       

       

      ----------------------------------------------------------------------------

       

      本帖第一、第三個示例,執(zhí)行時并不會啟動 MS DTC;而第二個示例,則要看 TransactionScopeOption 的設(shè)置情形,依本帖下載示例的缺省值,由于雙方都為 Required,因此默認會啟動 DTC;但若您將示例中 Class 2 里 func 2 改為 RequiresNew,則不會啟動 DTC。因此實務(wù)上,一個系統(tǒng)該如何去設(shè)計,是否要為了徹底的組件化、易于日后維護和擴展,而犧牲一些事務(wù)處理上的性能 (寫 Java/J2EE 的人好像常干這種事),應(yīng)視系統(tǒng)和項目的需求,而非永遠以一套固定的設(shè)計方式或代碼寫法,就想套用在所有的項目中。

      圖 3 MS DTC 統(tǒng)計畫面

       

      ----------------------------------------------------------------------------

       

      相關(guān)文章:

      [1] Introducing System.Transactions in the .NET Framework 2.0
      http://msdn.microsoft.com/en-us/library/ms973865.aspx

      [2] J2EE與.NET在Transaction Scope上的比較
      http://www.rzrgm.cn/perhaps/archive/2005/08/17/216863.html

      [3] SQL Server 的 System.Transactions 集成 (ADO.NET)
      http://msdn.microsoft.com/zh-cn/library/ms172070.aspx

      [4] 談?wù)劮植际绞聞?wù)(Distributed Transaction)[共5篇] - Artech - 博客園
      http://www.rzrgm.cn/artech/archive/2010/01/31/1660433.html

      [5] WCF系列_分布式事務(wù)
      http://www.rzrgm.cn/chnking/archive/2010/01/10/1643362.html
      http://www.rzrgm.cn/chnking/archive/2010/01/10/1643384.html

      [6] 網(wǎng)站性能優(yōu)化 - 數(shù)據(jù)庫及服務(wù)器架構(gòu)篇
      http://www.rzrgm.cn/WizardWu/archive/2009/09/22/1571499.html

       

      ----------------------------------------------------------------------------

       

      posted on 2010-02-04 03:18  WizardWu  閱讀(5728)  評論(8)    收藏  舉報
      主站蜘蛛池模板: 日韩免费无码视频一区二区三区| 日韩人妻av一区二区三区| 国产午夜福利精品视频| 精品无码人妻一区二区三区| 国产亚洲欧洲AⅤ综合一区| 亚洲一区二区三区激情视频| 国产精品中文第一字幕| 黄色A级国产免费大片视频| 国产成人一区二区三区视频免费| 国产精品无码无需播放器| 欧美日韩国产亚洲沙发| 欧美激情内射喷水高潮| 性欧洲大肥性欧洲大肥女| 激情国产av做激情国产爱| 亚洲精品一区二区三区大桥未久| 亚洲18禁一区二区三区| 国产精品日韩av一区二区| 国产成人无码av一区二区| 日韩AV高清在线看片| 国产乱子伦视频在线播放| 无套内谢少妇毛片aaaa片免费| 成人免费无码视频在线网站| 国产精品黄色片| 亚洲国产精品一区第二页| 色欲aⅴ亚洲情无码av蜜桃| 日日碰狠狠添天天爽五月婷 | 亚洲精品一区二区三天美| 欧洲尺码日本尺码专线美国又| 97久久精品人人做人人爽| 九九热在线这里只有精品| 丰满熟妇人妻中文字幕| 亚洲AV无码不卡在线播放| 亚洲精品成人综合色在线| 免费区欧美一级猛片| 日韩丝袜人妻中文字幕| 成人午夜福利精品一区二区| 加勒比无码人妻东京热| 综合图区亚洲欧美另类图片| 天天躁久久躁日日躁| 99精品国产精品一区二区| 无码人妻斩一区二区三区|