delphi组件:用Delphi模拟组件的两阶段提交

问题提出:写了个数据库操作类TDBOperate_DL对数据库操作嘛提供了声明事务开始、提交事务和回滚事务思路方法供其他类

TDBOperate_DL =

  private

    ADOC:TADOConnection;

    ADOQ:TADOQuery;

    isDestroyADOC:Boolean;    //是否销毁自己ADOC?

    fIsInTrans:Boolean;        //是否已经开始事务

  public

    isCommit:Boolean;         //是否要提交事务缺省是真如果有类投票说反对提交就为假

    function IsInTrans:Boolean;

    constructor Create(const ADOC: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 GetData(const sqlString:String):_Record;

    function GetConnection:TADOConnection;

    procedure SetConnection(const ADOC: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;

解决思路方法两阶段提交先粘点背景知识:

不论两层或 3层体系事物处理都是通过两阶段提交实现在第阶段每个执行资源\记录被写入 事物环境(Transcation Context)中,然后资源协调者顺序查询每个参和事物执行是否成功如果都没有问题就进入第 2阶段每个执行都开始Commit它操作如果有个执行有问题资源协调者通知所有下属执行放弃Commit,恢复数据原状态

参考COM+事务运行如果个组件是需要事务那么在组件创建时事务就已经开始了在组件销毁时进行事务投票如果是根事务则进行提交或回滚事务(如果组件支持池化这两种情况发生在组件激活和休眠事件中)于是我们定义个类如下

//业务类祖先类用于提供统事务支持

  TTS_DL =

  private

    isRootTrans:Boolean;      //是否是根事务

    isNeedTrans:Boolean;      //是否需要事务

  public

    DBOperate:TDBOperate_DL;   //操作数据库例子

    procedure SetComplete;

    procedure SetAbort;

    constructor Create(const DBOperate:TDBOperate_DL;needTrans:Boolean);//是否需要事务支持

    destructor Destroy;override;

  end;

在该类创建时除了传递进操作数据库例子外再传入个是否需要事务标志如果是只做读取数据库操作就用不着事务了

类实现代码如下:

constructor TTS_DL.Create(const DBOperate: TDBOperate_DL;

  needTrans: Boolean);

begin

  inherited Create;

  self.DBOperate := DBOperate;              

  self.isNeedTrans := needTrans;                     //赋值是否需要事务

   self.isNeedTrans then

  begin

    //如果在事务里就不是根事务保留事务上下文里isCommit值不变

     self.DBOperate.isInTrans then

      self.isRootTrans := false

    

    begin

      self.DBOperate.BeginTrans;           //是根事务就开始事务

      self.isRootTrans := true;

      self.DBOperate.isCommit := true;       //化提交标志为要提交事务

    end;

  end;

end;



destructor TTS_DL.Destroy;

begin

   self.isNeedTrans then

  begin

    //如果是根事务就按照投票结果进行事务提交或回滚

     self.isRootTrans then

    begin

       self.DBOperate.isCommit then

        self.DBOperate.CommitTrans

      

        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 = (TTS_DL);

       Tperson = (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搞定

个版本水平有限还需要在实际应用中完善全当抛砖引玉请有经验大侠们拍砖吧:)
Tags:  delphiasp组件 delphi组件开发 delphi组件大全 delphi组件

延伸阅读

最新评论

发表评论