程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 用Delphi模擬組件的兩階段提交

用Delphi模擬組件的兩階段提交

編輯:Delphi
問題提出:寫了一個數據庫操作的類TDBOperate_DL,統一對數據庫的操作嘛。提供了聲明事務開始、提交事務和回滾事務的方法供其他類調用。 TDBOperate_DL = class   private     ADOC:TADOConnection;     ADOQ:TADOQuery;     isDestroyADOC:Boolean;    //是否銷毀自己的ADOC?     fIsInTrans:Boolean;        //是否已經開始事務   public     isCommit:Boolean;         //是否要提交事務,缺省是真,如果有類投票說反對提交,就為假     function IsInTrans:Boolean;     constructor Create(const newADOC:TADOConnection);overload;     constructor Create(const ServerName,DataBaseName,UserID,PassWord:String);overload;     destructor Destroy;override;     procedure BeginTrans;     procedure CommitTrans;     procedure RollbackTrans;     procedure Execute(const sqlString:String);     function GetDataset(const sqlString:String):_Recordset;     function GetConnection:TADOConnection;     procedure SetConnection(const newADOC:TADOConnection);   end;        一些函數的實現: procedure TDBOperate_DL.BeginTrans;          //開始事務 begin   self.ADOC.BeginTrans;   self.fIsInTrans := true; end;   procedure TDBOperate_DL.CommitTrans;              //提交事務 begin   self.ADOC.CommitTrans;   self.fIsInTrans := false; end;   procedure TDBOperate_DL.RollbackTrans;              //回滾事務 begin   self.ADOC.RollbackTrans;   self.fIsInTrans := false; end;   function TDBOperate_DL.IsInTrans: Boolean;         //查看事務是否已開始 begin   result := self.fIsInTrans; end;   寫了一個TThing類,用於向數據庫中添加、修改或刪除有關某種東西的記錄,調用TDBOperate_DL類完成。為了調用方便,因此有關的事務就放在了TThing類中,外部調用時不用考慮事務了。 如: procedure Tthing.Drop(const thing:String); var   sqlString:String; begin   sqlString := 刪除的SQL語句;   self.DBOperate.BeginTrans;           // DBOperate是TDBOperate_DL類型的私有變量,創建Tthing類實例時傳入的參數。   try     self.DBOperate.Execute(sqlString);     self.DBOperate.CommitTrans;   except     self. DBOperate.RollbackTrans;     raise;   end; end; 後來又寫了個TPerson類,用於向數據庫中添加、修改或刪除有關人的記錄。同樣事務放在了TPerson類中,現在我想刪除人的記錄時順便調用TThing類刪除和人有關的東西,事務問題就出現啦:事務不能嵌套啊。如果先刪除TThing,再重新聲明事務刪除TPerson,如果TPerson出錯,還怎麼回滾TThing? 如: procedure Tperson.Drop(const person:String); var   sqlString:String;   thing:Tthing; begin   sqlString := 刪除的SQL語句;   thing := Tthing.Create(self.DBOperate);              //TDBOperate_DL類型的DBOperate是作為參數傳進去的。   Self.DBOperate.BeginTrans;   Try     Thing.Drop(person);               //裡面有事務見上面的代碼     Self.DBOperate.Execute(sqlString);     self.DBOperate.CommitTrans;   except     self.DBOperate.RollbackTrans;     raise;   end; end; 解決方法,兩階段提交,先粘點背景知識: 不論兩層或三層體系,事物處理都是通過兩階段提交實現的。在第一階段,每個執行的的資源記錄被寫入 事物環境(Transcation Context)中,然後資源協調者順序查詢每一個參與事物的執行是否成功,如果都沒有問題的話,就進入第二階段,每個執行都開始Commit它的操作。如果有一個執行有問題的話,資源協調者通知所有下屬的執行放棄Commit,恢復數據原狀態。 參考COM+的事務運行,如果一個組件是需要事務的,那麼在組件創建時,事務就已經開始了,在組件銷毀時進行事務投票,如果是根事務,則進行提交或回滾事務。(如果組件支持池化,這兩種情況發生在組件激活和休眠事件中)。於是我們定義一個類如下。 //業務類的祖先類,用於提供統一的事務支持   TTS_DL = class   private     isRootTrans:Boolean;      //是否是根事務     isNeedTrans:Boolean;      //是否需要事務   public     DBOperate:TDBOperate_DL;   //操作數據庫的類的實例     procedure SetComplete;     procedure SetAbort;     constructor Create(const newDBOperate:TDBOperate_DL;needTrans:Boolean);//是否需要事務支持     destructor Destroy;override;   end; 在該類創建時,除了傳遞進操作數據庫的類的實例外,再傳入一個是否需要事務的標志,因為如果是只做讀取數據庫的操作,就用不著事務了。 類實現代碼如下: constructor TTS_DL.Create(const newDBOperate: TDBOperate_DL;   needTrans: Boolean); begin   inherited Create;   self.DBOperate := newDBOperate;                self.isNeedTrans := needTrans;                     //賦值是否需要事務   if self.isNeedTrans then   begin     //如果在事務裡,就不是根事務,保留事務上下文裡isCommit的值不變     if self.DBOperate.isInTrans then       self.isRootTrans := false     else     begin       self.DBOperate.BeginTrans;           //是根事務,就開始事務       self.isRootTrans := true;       self.DBOperate.isCommit := true;       //初始化提交標志為要提交事務     end;   end; end;   destructor TTS_DL.Destroy; begin   if self.isNeedTrans then   begin     //如果是根事務,就按照投票結果進行事務提交或回滾     if self.isRootTrans then     begin       if self.DBOperate.isCommit then         self.DBOperate.CommitTrans       else         self.DBOperate.RollbackTrans;     end;   end;   inherited; end;   procedure TTS_DL.SetAbort; begin   self.DBOperate.isCommit := self.DBOperate.isCommit And false;       //投票說要回滾 end;   procedure TTS_DL.SetComplete; begin   self.DBOperate.isCommit := self.DBOperate.isCommit And true; //投票說要提交 end;   回到剛才的業務類Tthing和Tperson,這次都從TTS_DL類繼承下來。        Tthing = class(TTS_DL);        Tperson = class(TTS_DL); Tthing的刪除代碼該為如下: procedure Tthing.Drop(const thing:String); var   sqlString:String; begin   sqlString := 刪除的SQL語句;   try     self. DBOperate.Execute(sqlString);     self. DBOperate.SetComplete;         //投票提交   except     self. DBOperate.SetAbort;                     //投票回滾     raise;   end; end; Tperson的刪除代碼如下: procedure Tperson.Drop(const person:String); var   sqlString:String;   thing:Tthing; begin   sqlString := 刪除的SQL語句;   thing := Tthing.Create(self. DBOperate,true);              //TDBOperate_DL類型的DBOperate是作為參數傳進去的,true代表需要事務。   Try     Try       Thing.Drop(person);       Self.DBOperate.Execute(sqlString);       self.DBOperate.SetComplete;           //投票提交     except       self. DBOperate.SetAbort;                       //投票回滾       raise;     end;   finally     thing.free;                                                           //記著一定要釋放   end; end; 記著保持程序中使用唯一的操作數據庫類TDBOperate_DL的實例,記著釋放業務類實例,如果是需要事務的,盡量早釋放,OK,搞定。 第一個版本,水平有限,還需要在實際應用中完善,全當拋磚引玉,請有經驗的大俠們拍磚吧:)
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved