IdHTTPserver: Поделиться ADOConnection - PullRequest
2 голосов
/ 16 сентября 2011

Я создаю простой веб-сервер Indy, используя TIdHTTPServer .Почти по всем запросам сервер должен связываться с базой данных (через TAdoConnection ).Видя, что соединения с базой данных довольно дороги с точки зрения ресурсов, я хотел бы создать механизм объединения для повторного использования соединений;вместо того, чтобы устанавливать соединение по каждому запросу.

Я безуспешно искал примеры. Эта ссылка на форумах Embarcadero предлагает подклассы потомков TIdSchedulerOfThreadPool и TIdThreadWithTask .Но я все еще не могу собрать все это вместе.

Нужно ли мне переопределить метод TIdSchedulerOfThreadPool.NewThread и вернуть ему субклассированный TIdThreadWithTask объект, который, в свою очередь, будет иметь собственный TAdoConnection объект?

У кого-нибудь есть пример?Стоит ли мне даже не беспокоиться об этом и просто открывать соединение с базой данных при каждом запросе?

Ответы [ 2 ]

4 голосов
/ 16 сентября 2011

Вы также должны убедиться, что COM настроен правильно в каждом потоке с помощью вызова пары: CoInitialize / CoUnitialize

Ниже приведен пример блока для включения в ваш проект. А в конструкторе вашего HTTP-сервера просто создайте свой собственный планировщик, и Indy будет использовать его вместо значения по умолчанию.

Если вы сделаете это, то каждый поток клиента будет правильно инициализирован для COM, и вы также можете добавить другие элементы, которые будут общими для всех потоков клиента.

Я также создаю собственный потомок TIdServerContext для каждого соединения (и также устанавливаю свойство ContextClass в конструкторе HTTP-сервера.) Разные типы серверов имеют разных потомков TIdServerContext, но все они используют класс базового потока TsoIndyCOMEnabledSchedulerOfThread, как и все они. COM какой-то.

Я бы не помещал соединение ADO в поток, а скорее в контекст ... особенно если вы перенесете это дальше в пул потоков.

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;
4 голосов
/ 16 сентября 2011

Почему вы сами не управляете бассейном?

У вас есть список подключений. Это начинается пусто. Каждый раз, когда приходит запрос, вы ищите доступные соединения (соединения, которые активны, но не используются). Если ничего не найдено, вы создаете его и помещаете в список как недоступный. Как только запрос заканчивается, вы устанавливаете соединение как доступное.

Был там, сделал это, не жалей об этом вообще! Несколько проблемных моментов:

  • Всегда помните о безопасности нитей:
    • Когда вы запрашиваете список
    • Когда вы запрашиваете доступность соединения
    • Когда вы устанавливаете доступность соединения
  • Время от времени проверяйте, имеется ли у вас слишком много доступных неиспользуемых подключений, может быть, их больше, чем нужно, поэтому они должны быть недоступны, удалены из списка и затем закрыты.
...