多層資料庫應用基於Delphi DataSnap方法調用的實現—–對象池技術

來源:互聯網
上載者:User

       之前說到中介層通過向用戶端暴露方法的方式提供服務,實現資料庫資料的讀取和更新。方法調用的方式,其潛在的意義,就是說中介層不儲存用戶端狀態資訊,就像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;

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.