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搞定
第个版本水平有限还需要在实际应用中完善全当抛砖引玉请有经验大侠们拍砖吧:)
最新评论