简体   繁体   English

IdHTTPserver:共享ADOConnection

[英]IdHTTPserver: Share ADOConnection

I am creating a simple Indy webserver using TIdHTTPServer . 我正在使用TIdHTTPServer创建一个简单的Indy网络服务器。 On almost all request the server needs to communicates with a database (via TAdoConnection ). 在几乎所有请求中,服务器都需要与数据库通信(通过TAdoConnection )。 Seeing that database connections are somewhat expensive in terms of resources, I would like to create a pooling mechanism to reuse connections; 看到数据库连接在资源方面有点昂贵,我想创建一个池重用连接的池机制; rather than making the connection on each request. 而不是在每个请求上建立连接。

I have searched unsuccessfully for examples. 我搜索的例子没有成功。 This Link on Embarcadero Discussion Forums suggests sub-classing descendents of TIdSchedulerOfThreadPool and TIdThreadWithTask . 这篇关于Embarcadero论坛的链接建议对TIdSchedulerOfThreadPoolTIdThreadWithTask的后代进行子类 But I still cannot get it all together. 但我仍然无法将它们全部融合在一起。

Will I need to override the TIdSchedulerOfThreadPool.NewThread method and have it return my sub-classed TIdThreadWithTask object which in turn would have it's own TAdoConnection object? 我是否需要覆盖TIdSchedulerOfThreadPool.NewThread方法并让它返回我的子类TIdThreadWithTask对象,而该对象又拥有自己的TAdoConnection对象?

Does anyone have an example? 有人有例子吗? Should I not even worry about this and just open the database connection on each request? 我是否应该不担心这一点,只是在每个请求上打开数据库连接?

Why don't you manage the pool yourself? 你为什么不亲自管理游泳池?

You have a list of connections. 你有一个连接列表。 It starts empty. 它开始是空的。 Every time a request comes, you look for available connections (connections which are active but not being used). 每次请求到来时,您都会查找可用的连接(活动但未使用的连接)。 If none are found, you create one and put it in the list, as unavailable. 如果没有找到,则创建一个并将其放入列表中,作为不可用。 Once the request ends, you set the connection to available. 请求结束后,将连接设置为可用。

Been there, done that, do not regret doing it at all! 在那里,做到了,不要后悔这样做! A few points of concern: 几个值得关注的问题:

  • Keep thread safety in mind all times: 始终牢记线程安全:
    • When you query the list 查询列表时
    • When you query a connection's availability 查询连接的可用性时
    • When you set a connection's availability 设置连接的可用性时
  • From time to time, check if you have too many unused connections available, there might be more than you need, so they must be set to unavailable, removed from the list and then closed. 有时,检查是否有太多未使用的连接可用,可能比您需要的多,因此必须将它们设置为不可用,从列表中删除然后关闭。

You also have to ensure COM is setup correctly in each thread with a call to the pair: CoInitialize/CoUnitialize 您还必须确保在每个线程中正确设置COM并调用该对:CoInitialize / CoUnitialize

Below is an example unit to include in your project. 下面是要包含在项目中的示例单位。 And in your HTTP server constructor simply create your custom scheduler and Indy will use this instead of the default. 在您的HTTP服务器构造函数中,只需创建自定义调度程序,Indy将使用它而不是默认值。

If you do this, then each client thread will be properly initialized for COM and you can also add other items that will be shared by all client threads. 如果执行此操作,则将为COM正确初始化每个客户端线程,并且还可以添加将由所有客户端线程共享的其他项。

I also create a custom TIdServerContext descendant for each connection (and set the ContextClass property in the HTTP Server constructor as well.) Different types of servers have different TIdServerContext descendants, but they all utilize the TsoIndyCOMEnabledSchedulerOfThread base thread class as they all do COM of some sort. 我还为每个连接创建了一个自定义TIdServerContext后代(并在HTTP Server构造函数中设置了ContextClass属性。)不同类型的服务器具有不同的TIdServerContext后代,但它们都使用TsoIndyCOMEnabledSchedulerOfThread基本线程类,因为它们都执行某些COM分类。

I wouldn't put the ADO Connection into the Thread, but rather into the Context...especially if you carry this further into a thread pool. 我不会将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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM