Выполнение запросов к базе данных в фоне

=== Выполнение запросов к базе данных в фоне ===
Данный документ объясняет как выполнить запрос в фоновом режиме, используя класс TThread. Для получения общей информации о классе TThread, пожалуйста обратитесь к документации Borland и электронной справке. Для понимания данного документа вам необходимо иметь представление о том, как работать с компонентами для работы с базами данных, поставляемых в комплекте с Delphi 2.0.
Для осуществления потокового запроса необходимо выполнение двух требований. Во-первых, потоковый запрос должен находиться в своей собственной сессии с использованием отдельного компонента TSession. Следовательно, на вашей форме должен находиться компонент TSession, имя которого должно быть назначено свойству SessonName компонента TQuery, используемого для выполнения потокового запроса. Для каждого используемого в потоке компонента TQuery вы должны использовать отдельный компонент TSession. При использовании компонента TDataBase, для отдельного потокового запроса должен также использоваться отдельный TDataBase. Второе требование заключается в том, что компонент TQuery, используемый в потоке, не должен подключаться в контексте это потока к TDataSource. Это должно быть сделано в контексте первичного потока.
Приведенный ниже пример кода иллюстрирует описываемый процесс. Данный модуль демонстрирует форму, которая содержит по два экземпляра следующих компонентов: TSession, TDatabase, TQuery, TDataSource и TDBGrid. Данные компоненты имеют следующие значения свойств:
 Session1
 Active True;
 SessionName "Ses1"
 
 DataBase1
 AliasName "IBLOCAL"
 DatabaseName "DB1"
 SessionName "Ses1"
 
 Query1
 DataBaseName "DB1"
 SessionName "Ses1"
 SQL.Strings "SELECT * FROM employee"
 
 DataSource1
 DataSet ""
 
 DBGrid1
 DataSource DataSource1
 
 Session2
 Active True;
 SessionName "Ses2"
 
 DataBase2
 AliasName "IBLOCAL"
 DatabaseName "DB2"
 SessionName "Ses2"
 
 Query2
 DataBaseName "DB2"
 SessionName "Ses2"
 SQL.Strings "SELECT * FROM customer"
 
 DataSource2
 DataSet ""
 
 DBGrid1
 DataSource DataSource2
Обратите внимание на то, что свойство DataSet обоих компонентов TDataSource первоначально никуда не ссылается. Оно устанавливается во время выполнения приложения, и это проиллюстрировано в коде.
unit Unit1;
interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls,
 Forms, Dialogs, StdCtrls, Grids, DBGrids, DB, DBTables;
type
 TForm1 = class(TForm)
 Session1: TSession;
 Session2: TSession;
 Database1: TDatabase;
 Database2: TDatabase;
 Query1: TQuery;
 Query2: TQuery;
 DataSource1: TDataSource;
 DataSource2: TDataSource;
 DBGrid1: TDBGrid;
 DBGrid2: TDBGrid;
 GoBtn1: TButton;
 procedure GoBtn1Click(Sender: TObject);
 end;
 TQueryThread = class(TThread)
 private
 FSession: TSession;
 FDatabase: TDataBase;
 FQuery: TQuery;
 FDatasource: TDatasource;
 FQueryException: Exception;
 procedure ConnectDataSource;
 procedure ShowQryError;
 protected
 procedure Execute; override;
 public
 constructor Create(Session: TSession; DataBase:
 TDatabase; Query: TQuery; DataSource: TDataSource);
 virtual;
 end;
var
 Form1: TForm1;
implementation
constructor TQueryThread.Create(Session: TSession; DataBase: TDatabase;
 Query: TQuery; Datasource: TDataSource);
begin
 inherited Create(True); // Создаем поток c состоянием suspendend
 FSession := Session; // подключаем все privat-поля
 FDatabase := DataBase;
 FQuery := Query;
 FDataSource := Datasource;
 FreeOnTerminate := True; // Устанавливаем флаг освобождения потока после его завершения
 Resume; // Продолжение выполнения потока
end;
procedure TQueryThread.Execute;
begin
 try
 { Выполняем запрос и подключаем источник данных к компоненту TQuery,
 вызывая ConnectDataSource из основного потока
 (для этой цели используем Synchronize) }
 FQuery.Open;
 Synchronize(ConnectDataSource);
 except
 { Ловим исключение (если оно происходит) и его дескриптор
 в контексте основного потока (для этой цели используем Synchronize). }
 FQueryException := ExceptObject as Exception;
 Synchronize(ShowQryError);
 end;
end;
procedure TQueryThread.ConnectDataSource;
begin
 FDataSource.DataSet := FQuery; // Подключаем DataSource к TQuery
end;
procedure TQueryThread.ShowQryError;
begin
 Application.ShowException(FQueryException); // Обрабатываем исключение
end;
procedure RunBackgroundQuery(Session: TSession; DataBase: TDataBase; Query:
 TQuery; DataSource: TDataSource);
begin
 { Создаем экземпляр TThread с различными параметрами. }
 TQueryThread.Create(Session, Database, Query, DataSource);
end;
{$R *.DFM}
procedure TForm1.GoBtn1Click(Sender: TObject);
begin
 { Запускаем два отдельных запроса, каждый в своем потоке }
 RunBackgroundQuery(Session1, DataBase1, Query1, Datasource1);
 RunBackgroundQuery(Session2, DataBase2, Query2, Datasource2);
end;
end.
Метод TForm1.GoBtn1Click является обработчиком события нажатия кнопки. Данный обработчик события дважды вызывает процедуру RunBackgroundQuery, это случается при каждой передаче новых параметров компонентам для работы с базой данных. RunBackgroundQuery создает отдельный экземпляр класса TQueryThread, передает различные компоненты для работы с базой данных в его конструктор, который, в свою очередь, назначает их закрытым полям TQueryThread.
TQueryThread содержит две определенные пользователем процедуры: ConnectDataSource и ShowQryError. ConnectDataSource связывает FDataSource.DataSet с FQuery. Тем не менее, это делается в первичном потоке с помощью метода TThread.Synchronize. ShowQryError обрабатывает исключение в контексте первичного потока, также используя метод Synchronize. Конструктор Create и метод Execute снабжены подробными комментариями.
Source: Взято с http://delphiworld.narod.ru
ID: 02632