<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        在.NET2.0中使用自定義事務操作

        來源:懂視網 責編:小采 時間:2020-11-27 22:45:45
        文檔

        在.NET2.0中使用自定義事務操作

        在.NET2.0中使用自定義事務操作:.net 2.0 framework 中新增了 System.Transactions 命名空間,其中提供的一系列接口和類使得在.net 2.0 中使用事務比起從前要方便了許多。有關在 .net 2.0 下操作數據庫事務的文章已經有了很多,這里只提一下如何設計自定義事務操作。 一、事務使用基礎
        推薦度:
        導讀在.NET2.0中使用自定義事務操作:.net 2.0 framework 中新增了 System.Transactions 命名空間,其中提供的一系列接口和類使得在.net 2.0 中使用事務比起從前要方便了許多。有關在 .net 2.0 下操作數據庫事務的文章已經有了很多,這里只提一下如何設計自定義事務操作。 一、事務使用基礎

          .net 2.0 framework 中新增了 System.Transactions 命名空間,其中提供的一系列接口和類使得在.net 2.0 中使用事務比起從前要方便了許多。有關在 .net 2.0 下操作數據庫事務的文章已經有了很多,這里只提一下如何設計自定義事務操作。

          一、事務使用基礎

          先看一段使用事務的代碼:

        1using (TransactionScope ts= new TransactionScope())
        2{
        3 //自定義操作
        4 ts.Complete();
        5}
          這里使用 using 語句定義了一段隱性事務。如果我們在該語句塊中加入一段對 SQL Server 操作的代碼,那么它們將會自動加入這個事務。可以看出,這種事務的使用方式是極其方便的。

          那么,有沒有可能在該語句塊中加入我們自己定義的事務操作,并且該操作能夠隨著整個事務塊的成功而提交,隨其失敗而回滾呢?答案當然是可以的,否則我就不會寫這篇隨筆了。

          二、實現自定義事務操作

          根據事務的特性,我們可以推想:這個操作必須有實現提交和回滾之類動作的方法。沒錯,這就是 System.Transactions 命名空間中的 IEnlistmentNotification 接口。我們先寫一個最簡單的實現:

        1class SampleEnlistment1 : IEnlistmentNotification
        2{
        3 void IEnlistmentNotification.Commit(Enlistment enlistment)
        4 {
        5 Console.WriteLine("提交!");
        6 enlistment.Done();
        7 }
        8
        9 void IEnlistmentNotification.InDoubt(Enlistment enlistment)
        10 {
        11 throw new Exception("The method or operation is not implemented.");
        12 }
        13
        14 void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
        15 {
        16 Console.WriteLine("準備!");
        17 preparingEnlistment.Prepared();
        18 }
        19
        20 void IEnlistmentNotification.Rollback(Enlistment enlistment)
        21 {
        22 Console.WriteLine("回滾!");
        23 enlistment.Done();
        24 }
        25}
        26
        27
          好,定義完之后,還需要向事務管理器進行注冊,把它加入到當前事務中去:

        1using (TransactionScope ts= new TransactionScope())
        2{
        3 SampleEnlistment1 myEnlistment1 = new SampleEnlistment1();
        4 Transaction.Current.EnlistVolatile(myEnlistment1, EnlistmentOptions.None);
        5 ts.Complete();
        6}
          執行這一段代碼,我們可以得到以下的輸出:

          準備!
          提交!

          先解釋一下,當調用 ts.Complete() 方法的時候,表示事務已成功執行。隨后,事務管理器就會尋找當前所有已注冊的條目,也就是 IEnlistmentNotification 的每一個實現,依次調用它們的 Prepare 方法,即通知每個條目做好提交準備,當所有條目都調用了 Prepared() 表示自己已經準備妥當之后,再依次調用它們的 Commit 方法進行提交。如果其中有一個沒有調用 Prepared 而是調用了 ForceRollback 的話,整個事務都將回滾,此時事務管理器再調用每個條目的 Rollback 方法。

          而如果我們將前面的 ts.Complete() 行注釋掉,顯然執行結果就將變為:

          回滾!

          三、一個實現賦值的自定義操作

          考慮一下,我們要實現一個事務賦值操作。該如何做法?以下是一個例子:

        1class SampleEnlistment2 : IEnlistmentNotification
        2{
        3 public SampleEnlistment2(AssignTransactionDemo var, int newValue)
        4 {
        5 _var = var;
        6 _oldValue = var.i;
        7 _newValue = newValue;
        8 }
        9
        10 private AssignTransactionDemo _var;
        11 private int _oldValue;
        12 private int _newValue;
        13
        14 void IEnlistmentNotification.Commit(Enlistment enlistment)
        15 {
        16 _var.i = _newValue;
        17 Console.WriteLine("提交!i的值變為:" + _var.i.ToString());
        18 enlistment.Done();
        19 }
        20
        21 void IEnlistmentNotification.InDoubt(Enlistment enlistment)
        22 {
        23 throw new Exception("The method or operation is not implemented.");
        24 }
        25
        26 void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
        27 {
        28 preparingEnlistment.Prepared();
        29 }
        30
        31 void IEnlistmentNotification.Rollback(Enlistment enlistment)
        32 {
        33 _var.i = _oldValue;
        34 Console.WriteLine("回滾!i的值變為:" + _var.i.ToString());
        35 enlistment.Done();
        36 }
        37}
        38
        39class AssignTransactionDemo
        40{
        41 public int i;
        42
        43 public void AssignIntVarValue(int newValue)
        44 {
        45 SampleEnlistment2 myEnlistment2 = new SampleEnlistment2(this, newValue);
        46 Guid guid = new Guid("{3456789A-7654-2345-ABCD-098765434567}");
        47 Transaction.Current.EnlistDurable(guid, myEnlistment2, EnlistmentOptions.None);
        48 }
        49}
        50
        51
          然后,這樣來使用:

        1AssignTransactionDemo atd = new AssignTransactionDemo();
        2atd.i = 0;
        3using (TransactionScope scope1 = new TransactionScope())
        4{
        5 atd.AssignIntVarValue(1);
        6 Console.WriteLine("事務完成!");
        7 scope1.Complete();
        8 Console.WriteLine("退出區域之前,i的值為:" + atd.i.ToString());
        9}
        10Thread.Sleep(1000);
        11Console.WriteLine("退出區域之后,i的值為:" + atd.i.ToString());
          運行這一段代碼,我們可以看到如下結果:

          事務完成!
          退出區域之前,i的值為:0
          提交!i的值變為:1
          退出區域之后,i的值為:1

          從輸出結果來看,賦值操作被成功執行了。可是有沒有感覺有些奇怪?先做個討論:

          1、如果前面沒有 Thread.Sleep(1000) 這一行,那么我們多半會看到最后一行的輸出中,i 的值依然會是 0!為什么?想想就容易明白,這里對 Commit 方法是采用的異步調用,如同另開了一個線程。如果主線程不作等待的話,當輸出的時候事務的 Commit 方法多半還沒有被執行,輸出的結果當然就會不對。

          2、這個例子中,賦值操作是在 Commit 方法中才實際執行的。但實際上就本例而言,我們也可以做個調整:將賦值操作放在 AssignIntVarValue 方法的最后去執行,然后把 Commit 方法中的賦值操作去掉。相關的代碼變化如下:

        1class SampleEnlistment2 : IEnlistmentNotification
        2{
        3 void IEnlistmentNotification.Commit(Enlistment enlistment)
        4 {
        5 enlistment.Done();
        6 }
        7 //其它略
        8}
        9
        10class AssignTransactionDemo
        11{
        12 public int i;
        13
        14 public void AssignIntVarValue(int newValue)
        15 {
        16 SampleEnlistment2 myEnlistment2 = new SampleEnlistment2(this, newValue);
        17 Guid guid = new Guid("{3456789A-7654-2345-ABCD-098765434567}");
        18 Transaction.Current.EnlistDurable(guid, myEnlistment2, EnlistmentOptions.None);
        19 i = newValue;
        20 Console.WriteLine("提交前改變!i的值為:" + i.ToString());
        21 }
        22}
        23
        24
          這樣,執行結果將會變為:

          提交前改變!i的值為:1
          事務完成!
          退出區域之前,i的值為:1
          退出區域之后,i的值為:1

          3、在前面的基礎上,當把調用的地方作如下改動,使事務失敗:

        1using (TransactionScope scope1 = new TransactionScope())
        2{
        3 atd.AssignIntVarValue(1);
        4 Console.WriteLine("事務失敗!");
        5 //scope1.Complete();
        6 Console.WriteLine("退出區域之前,i的值為:" + atd.i.ToString());
        7}
          此時的執行結果將變為:

          提交前改變!i的值為:1
          事務失敗!
          退出區域之前,i的值為:1
          回滾!i的值變為:0
          退出區域之后,i的值為:0

          可見,事務已成功回滾。

          四、進一步的討論

          前面我們都是只進行了一次賦值操作,如果我們需要進行兩次呢?

        1using (TransactionScope scope1 = new TransactionScope())
        2{
        3 atd.AssignIntVarValue(1);
        4 atd.AssignIntVarValue(2);
        5 Console.WriteLine("事務失敗!");
        6 //scope1.Complete();
        7 Console.WriteLine("退出區域之前,i的值為:" + atd.i.ToString());
        8}
          這時的執行結果將會是如何?我們當然是希望回滾的時候,i 的值能先變回為 1,再變回為 0。但是實際結果呢?

          提交前改變!i的值為:1
          提交前改變!i的值為:2
          事務失敗!
          退出區域之前,i的值為:2
          回滾!i的值變為:0
          回滾!i的值變為:1
          退出區域之后,i的值為:1

          顯然,事務的回滾并沒有按照我們希望的順序來,是何原因?分析一下機制就能知道,事務管理器向每個條目發出回滾命令的時候只是發出了一個異步調用,并且很可能還是按登記的順序來發出的,這樣一來,Rollback 方法的調用順序顯然就不能保證了。

          這時,如果將 Rollback 方法作一個小調整:

        1void IEnlistmentNotification.Rollback(Enlistment enlistment)
        2{
        3 while (_var.i != _newValue)
        4 {
        5 Thread.Sleep(500);
        6 }
        7 _var.i = _oldValue;
        8 Console.WriteLine("回滾!i的值變為:" + _oldValue.ToString());
        9 enlistment.Done();
        10}
          再次運行之,結果就對了:

          提交前改變!i的值為:1
          提交前改變!i的值為:2
          事務失敗!
          退出區域之前,i的值為:2
          回滾!i的值變為:1
          回滾!i的值變為:0

          結果的正確其實并不是調用的順序就對了,只是 Rollback 方法在執行的時候先檢查一下 _newValue 的值是否與當前 i 的值一致,不一致的話就等上一會兒。在等待的過程中,另一個實例的 Rollback 方法被執行,而它檢查發現是匹配的,所以就會回滾到 1。第一個 Rollback 等待結束后再檢查發現匹配了,于是就回滾為 0。

          當然實際應用中,這種方法是極不可取的。且不說執行順序依然會有很大的風險,光是設計方式就有大問題。那么在實際應用中我們應當如何去做呢?這里只提供一下設計思想,具體的實現代碼不再列出了。

          在前面的例子中,兩次賦值共進行了兩次登記,這一點是引發不穩定性的起因。我們應當考慮,兩次賦值依然只登記一次,在第一次賦值的時候,建立一個 SampleEnlistment2 的實例并在 AssignTransactDemo 中保存下來,并且 SampleEnlistment2 需要記錄當前的操作。下一次賦值時,仍然使用這個實例,只進行操作記錄即可。這樣,當回滾的時候,它根據記錄的反順序執行回滾操作就可以了。

          再進一步呢?如果說有多個 Transaction 需要進行賦值操作呢?這時我們可以在 AssignTransactionDemo 類中加入一個 Dictionary<Transaction, SampleEnlistment2>,使用的時候根據 Transaction 去尋找相應的條目即可。

          本文討論暫到此為止。在微軟的101個例子中,有一個使用事務進行文件拷貝的例子。那里面有比較深入的實現。如果你還沒有看過,推薦去研究一下,相信你讀過此篇隨筆,研究它應當不再是個難題。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        在.NET2.0中使用自定義事務操作

        在.NET2.0中使用自定義事務操作:.net 2.0 framework 中新增了 System.Transactions 命名空間,其中提供的一系列接口和類使得在.net 2.0 中使用事務比起從前要方便了許多。有關在 .net 2.0 下操作數據庫事務的文章已經有了很多,這里只提一下如何設計自定義事務操作。 一、事務使用基礎
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 国产亚洲精aa成人网站| 国产成人免费福利网站| 亚洲AV无码久久精品色欲| 国产精品免费一区二区三区| 亚洲精品岛国片在线观看| 青娱乐在线免费观看视频| 免费A级毛片无码A∨男男| 国产亚洲视频在线观看| 亚洲爽爽一区二区三区| 国产日韩AV免费无码一区二区| 国产成人精品日本亚洲网站| 一级成人a毛片免费播放| 亚洲精品在线不卡| 亚洲精品动漫免费二区| 亚洲AV无码成人精品区日韩| 亚洲高清最新av网站| 国产成年无码久久久免费| 亚洲成人免费在线| A在线观看免费网站大全| 亚洲精品无码少妇30P| 久久久久亚洲精品无码网址 | 99久久精品毛片免费播放| 国产AV无码专区亚洲AV手机麻豆 | 亚洲一区欧洲一区| 免费国产综合视频在线看| 美女无遮挡拍拍拍免费视频 | yy6080亚洲一级理论| a级毛片免费观看视频| 精品丝袜国产自在线拍亚洲| 四虎影在线永久免费观看| 9久热精品免费观看视频| 亚洲嫩模在线观看| 成人国产mv免费视频| 久久国产精品萌白酱免费| 中文无码亚洲精品字幕| 国产成人99久久亚洲综合精品 | 亚洲区精品久久一区二区三区| 国产精品酒店视频免费看| 无码人妻一区二区三区免费看| 亚洲国产成人手机在线观看| 亚洲ⅴ国产v天堂a无码二区|