多层数据库应用基于Delphi DataSnap方法调用的实现(三)对象池技术

之前说到中间层通过向客户端暴露方法的方式提供服务,实现数据库数据的读取和更新。方法调用的方式,其潜在的意义,就是说中间层不保存客户端状态信息,就像WEB服务一样,客户端需要自己保存自己的状态信息。进一步说,就是中间层具体提供方法的业务对象实例,不是也不应该专属于某个客户端,它应该能够为不同的客户端调用提供服务。如果我们把业务对象实例放到对象池中集中存放,调用方法时随用随取,方法结束即放回池中。这样就可以实现业务对象实例服务于不同的客户端调用请求。更重要的是,利用对象池,能够最大化服务器各种资源的使用效率,而且对客户端的响应也更快了,因为业务对象实例早就创建好了,取来即用。

 

其实,DataSnap构架,已经为我们的这种构想提供了现实支持。简单的说,就是改造工厂类(TDSServerClass),把LifeCycle属性改为Invocation方式;在OnCreateInstance事件中从对象池中取业务类对象实例;在OnDestroyInstance事件中把业务类对象实例放回对象池。

...
procedure TsmMainForm.dssMethodsCreateInstance(
  DSCreateInstanceEventObject: TDSCreateInstanceEventObject);
begin
  DSCreateInstanceEventObject.ServerClassInstance := ServerMethodsPool.LockPoolObject;
end;

 

procedure TsmMainForm.dssMethodsDestroyInstance(
  DSDestroyInstanceEventObject: TDSDestroyInstanceEventObject);
begin
  ServerMethodsPool.UnlockPoolObject(TPersistent(DSDestroyInstanceEventObject.ServerClassInstance));
end;
...
当然,还有对象池类的创建和释放,也很简单,例如:
procedure TsmMainForm.FormCreate(Sender: TObject);
begin
  ServerMethodsPool := ObjPoolMgr.TPoolManager.Create;
  ServerMethodsPool.InstanceClass := uServerMethods.TPooledDM;
end;

 

procedure TsmMainForm.FormDestroy(Sender: TObject);
begin
  ServerMethodsPool.Free;
end;

 

下面就是如何实现对象池技术的问题。实现对象池并不复杂,另有两个问题需要注意:

1、多线程。中间层TDSTCPServerTransport对象提供的是多线程服务,允许同时有多个客户端请求。所以对象池类的实现,要考虑多线程情况下公共对象或变量的访问冲突问题。

2、内存泄漏。业务类的基类,采用TDataModule、TComponent或者TPersistent都可以,但不要采用TDSServerModule,因为若采用此基类,TDSServerClass在Invocation方式下会产生内存泄漏。

 

下面是对象池类最基本的实现代码:


unit ObjPoolMgr;

 

interface

 

uses
  Classes, SyncObjs, SysUtils, DSServer, DateUtils;

 

type

  PServerObject = ^TServerObject;
  TServerObject = record
    ServerObject: TPersistent;
    InUse:        Boolean;
  end;

 

  TPoolManager = class
  private
    FCriticalSection: TCriticalSection;
    FServerObjects:   TList;
  private
    FInstanceClass: TPersistentClass;
    function  CreateNewInstance: TPersistent; inline;
    procedure SetInstanceClass(const Value: TPersistentClass);
  public
    constructor Create;
    destructor Destroy; override;
    //从对象池中取出一个业务类实例对象
    function  LockPoolObject: TPersistent;
    //把一个业务类实例对象放回对象池中
    procedure UnlockPoolObject(var Value: TPersistent);
  public
    //指定放入池中的业务类。
    property InstanceClass: TPersistentClass read FInstanceClass write SetInstanceClass;
  end;

 

implementation

 

constructor TPoolManager.Create;
begin
  FServerObjects := TList.Create;
  FCriticalSection := TCriticalSection.Create;
end;

 

destructor TPoolManager.Destroy;
var
  I: Integer;
begin
  for I := 0 to FServerObjects.Count - 1 do
  begin
    PServerObject(FServerObjects[i]).ServerObject.Free;
    FreeMem(PServerObject(FServerObjects[i]));
  end;
  FServerObjects.Free;
  FCriticalSection.Free;
  inherited Destroy;
end;

 

procedure TPoolManager.SetInstanceClass(const Value: TPersistentClass);
begin
  FInstanceClass := Value;
end;

function TPoolManager.CreateNewInstance: TPersistent;
var
  p: PServerObject;
  Component: TComponent;
begin
  if not Assigned(FInstanceClass) then Raise Exception.Create('Not specify class of instance!');

  FCriticalSection.Enter;
  try
    if FInstanceClass.InheritsFrom(TComponent) then
    begin
      Component := FInstanceClass.NewInstance as TComponent;
      Component.Create(nil);
      Result := Component;
    end
    else
      Result := FInstanceClass.Create;

    New(p);
    p.ServerObject := Result;
    p.InUse        := True;
    FServerObjects.Add(p);
  finally
    FCriticalSection.Leave;
  end;
end;

 

function TPoolManager.LockPoolObject: TPersistent;
var
  i: Integer;
begin
  FCriticalSection.Enter;
  try
    for i := 0 to FServerObjects.Count - 1 do
    begin
      if not PServerObject(FServerObjects[I]).InUse then
      begin
        PServerObject(FServerObjects[I]).InUse := True;
        Result := PServerObject(FServerObjects[i]).ServerObject;
        Exit;
      end;
    end;
  finally
    FCriticalSection.Leave;
  end;
  Result := CreateNewInstance;
end;

 

procedure TPoolManager.UnlockPoolObject(var Value: TPersistent);
var
  i: Integer;
begin
  FCriticalSection.Enter;
  try
    for i := 0 to FServerObjects.Count - 1 do
    begin
      if Value = PServerObject(FServerObjects[i]).ServerObject then
      begin
        PServerObject(FServerObjects[i]).InUse := False;
        Value := nil;
        Break;
      end;
    end;
  finally
    FCriticalSection.Leave;
  end;
end;
...


上面的基本实现稍加修改,就可以完善更多的功能,比如设定实例数上限、定时清除超过某个时间未被使用的实例、查询当前池中对象实例数量等。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Delphi DataSnap数据是一种在Delphi环境下使用的数据库连接和数据存储技术。它可以帮助开发者在分布式应用程序中通过网络进行数据交互。 DataSnap 数据的核心概念是数据模块(Data Module),它提供了与数据库的连接和查询功能。数据模块可以包含多个数据集(DataSet),可以执行查询、插入、更新和删除操作。数据模块还具有数据源(DataSource)和数据集提供者(Provider)的功能,可以将数据源与数据集提供者进行绑定,从而将数据源的数据传输到客户端应用程序。 使用 Delphi DataSnap 数据,开发者可以通过远程数据集(RemoteDataSet)实现跨网络的数据访问。这种跨网络的数据交互是通过 DataSnap 服务器和客户端进行的。服务器端使用数据连接(Data Connection)建立与数据库的连接,客户端通过 DataSnap 连接器(DataSnap Connector)连接到服务器,并获取或更新数据。 Delphi DataSnap数据的优点是可以支持多种数据源(如数据库、文件和Web服务等),可以实现高效的数据交互。同时,它还具有安全性和性能优化的特性。开发者可以通过配置和设置来控制数据传输的安全性和性能。这使得开发分布式应用程序更加灵活和高效。 总之,Delphi DataSnap数据是一种强大的数据交互技术,能够帮助开发者实现分布式应用程序中的数据存储和访问。它是Delphi环境下开发分布式应用程序的重要工具之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值