简体   繁体   中英

IdHTTPserver: Share ADOConnection

I am creating a simple Indy webserver using TIdHTTPServer . On almost all request the server needs to communicates with a database (via 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 . 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?

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

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.

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.

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.

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.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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