IdHTTPserver:共享ADOConnection

时间:2011-09-16 15:25:54

标签: delphi connection-pooling indy

我正在使用 TIdHTTPServer 创建一个简单的Indy网络服务器。在几乎所有请求中,服务器都需要与数据库通信(通过 TAdoConnection )。看到数据库连接在资源方面有点昂贵,我想创建一个池重用连接的池机制;而不是在每个请求上建立连接。

我搜索的例子没有成功。关于Embarcadero论坛的This Link建议对 TIdSchedulerOfThreadPool TIdThreadWithTask 的后代进行子类化。但我仍然无法将它们全部融合在一起。

我是否需要覆盖 TIdSchedulerOfThreadPool.NewThread 方法并让它返回我的子类 TIdThreadWithTask 对象,而该对象又拥有自己的 TAdoConnection 对象?

有没有人有例子?我是否应该担心这一点,只是在每个请求上打开数据库连接?

2 个答案:

答案 0 :(得分:3)

你为什么不亲自管理游泳池?

您有一个连接列表。它开始是空的。每次请求到来时,您都会查找可用的连接(活动但未使用的连接)。如果没有找到,则创建一个并将其放入列表中,作为不可用。请求结束后,您将连接设置为可用。

去过那里,完成了,不要后悔这样做!有几点值得关注:

  • 始终牢记线程安全:
    • 查询列表时
    • 查询连接的可用性时
    • 设置连接可用性时
  • 不时检查您是否有太多未使用的连接可用,可能超出您的需要,因此必须将它们设置为不可用,从列表中删除然后关闭。

答案 1 :(得分:3)

您还必须确保在每个线程中正确设置COM并调用该对:CoInitialize / CoUnitialize

以下是要包含在项目中的示例单位。在您的HTTP服务器构造函数中,只需创建自定义调度程序,Indy将使用它而不是默认值。

如果执行此操作,则将为COM正确初始化每个客户端线程,并且还可以添加将由所有客户端线程共享的其他项。

我还为每个连接创建一个自定义TIdServerContext后代(并在HTTP Server构造函数中设置ContextClass属性。)不同类型的服务器具有不同的TIdServerContext后代,但它们都使用TsoIndyCOMEnabledSchedulerOfThread基本线程类,因为它们都是某种COM。

我不会将ADO Connection放入Thread中,而是放入Context中...尤其是如果你将其进一步放入线程池中。

unit ExampleStackOverflow;

interface

uses
  SysUtils, Classes,
  ActiveX,
  IdThread, IdSchedulerOfThreadDefault;

type
  //Meant to be used with a custom TIdSchedulerOfThreadDefault descendant
  //to ensure COM support on child threads.
  TsoIndyComThreadWithTask = class(TIdThreadWithTask)
  protected
    //Ensure COM is setup before client connection/thread work
    procedure BeforeExecute; override;
    //Graceful COM cleanup on client connection/thread
    procedure AfterExecute; override;
  end;


  TsoIndyCOMEnabledSchedulerOfThread = class(TIdSchedulerOfThreadDefault)
  public
    constructor Create(AOwner:TComponent); reintroduce;
  end;



implementation

procedure TsoIndyComThreadWithTask.BeforeExecute;
begin
  CoInitialize(nil);
  inherited;
end;


procedure TsoIndyComThreadWithTask.AfterExecute;
begin
  inherited;
  CoUninitialize();
end;


constructor TsoIndyCOMEnabledSchedulerOfThread.Create(AOwner:TComponent);
begin
  inherited;
  //the whole reason for overriding default scheduler of thread is to setup COM
  //on client threads
  ThreadClass := TsoIndyComThreadWithTask;
  Name := Name + 'COMEnabledScheduler';
end;