在C/S系统开发中,需要操作数据库,最简便的方法是使用TADOQuery,通常的做法是创建一个TDataModule,然后组合一个或多个TADOQuery部 件进行数据库操作。
这种方法简单实用,但也常常会带来一些问题,例如:外部调用者必须小心的使用TADOQuery,如果在同一时刻多处同时使用TADOQuery,结果 将不可预知;又例如:TDataModule中的TADOQuery在需要多个组合操作的场合会出现不够用的情况,此时,只能自已动态创建,而在操作较少时,在TDataModule模块中申请多个 TADOQuery则又会显得多余;
有什么办法可以让TDataModule中的TADOQuery够用呢,动态创建是一个不错的方法,但是有个问题:在TDataModule中创建的TADOQuery对象必须要等外部使用完毕后才能释放,那么这个释放的工作就必须交由外部调用者来完成。看似挺合理,但如果外部调用者使用后忘记释放,就会造成内存泄漏,而且一个对象的生命周期由多个对象来决定,本来就是有问题的。
希望解决上述的问题时,想到了接口的生存期自管理特性,可以利用接口的特性,将TADOQuery置于接口管理之下,在外部调用者使用完成后,自动回收TADOQuery对象,代码如下:
IRDataSet = interface(IUnknown)
function Exec(ASql: String; AExecMode: Boolean = False): TDataSet;
end;
TRDataSet = class(TInterfacedObject, IRDataSet)
private
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
FDataSet: TADOQuery;
constructor Create(AConn: TADOConnection);
destructor Destroy; override;
end;
{ TRDataSet }
function TRDataSet._AddRef: Integer;
begin
inherited _AddRef;
end;
function TRDataSet._Release: Integer;
begin
inherited _Release;
showmessage('释放了!');
if Assigned(FDataSet) then
begin
FDataSet.Close;
FreeAndNil(FDataSet);
end;
end;
constructor TRDataSet.Create(AConn: TADOConnection);
begin
FDataSet := TADOQuery.Create(nil);
FDataSet.Connection := AConn;
TADODataSet(FDataSet).CommandTimeout := 0;
FDataSet.Prepared := True;
end;
destructor TRDataSet.Destroy;
begin
inherited;
end;
如下引用:
var ADS: IRDataSet;
begin
ADS := TRDataSet.Create(nil);
showmessage('开始使用了!');
end;
貌似挺好,但要使用TADOQuery对象,还必须先定义一个IRDataSet,还是有点小麻烦。所以,应该有必要甩掉这个小尾巴。
这里采用的方法是:通过继承TCustomADODataSet来实现自已的TADOQuery,并使用具备生存期自管理功能。实现代码略。
既然可以对TADOQuery的生存周期进行管理了,那进一步想,可以根据外部使用的情况标记该TADOQuery的使用状态,在内部并不实时创建和释放。再进一步,将TADOQuery操作放到线程中执行,将可以有效的解决外部调用时界面僵死的状况。再再进一步,构建一个该对象的线程池,统一管理连接和使用,最后扩展相关代码后,便可形成一个相对通用且独立DB操作单元。
需要完成上述构思的关键类描述如下:
TCDataSet
继承于TCustomADODataSet的基类,完成自动回收的相关工作;
TCQuery
提供外部调用的可回收TADOQuery部件,用于支持一般查询及增删改操作;
TCDataSetThread
数据库操作管理线程;
TCDataSetConnect
封装TADOConnection后的可回收的连接部件,提供外部调用;
TDataFactory
对象工厂,负责完成基础的创建工作;
对象管理关系如下:
TDataFactory
|
--- TCDataSetConnect
|
--- TCDataSetThread
|
--- TCDataSet
|
--- TCQuery
由于实现代码太多,详细代码及示例请到:http://www.2ccc.com/article.asp?articleid=5119 下载,并欢迎提出意见交流!