我正在使用 TIdHTTPServer 创建一个简单的Indy网络服务器。在几乎所有请求中,服务器都需要与数据库通信(通过 TAdoConnection )。看到数据库连接在资源方面有点昂贵,我想创建一个池重用连接的池机制;而不是在每个请求上建立连接。
我搜索的例子没有成功。关于Embarcadero论坛的This Link建议对 TIdSchedulerOfThreadPool 和 TIdThreadWithTask 的后代进行子类化。但我仍然无法将它们全部融合在一起。
我是否需要覆盖 TIdSchedulerOfThreadPool.NewThread 方法并让它返回我的子类 TIdThreadWithTask 对象,而该对象又拥有自己的 TAdoConnection 对象?
有没有人有例子?我是否应该担心这一点,只是在每个请求上打开数据库连接?
答案 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;