Тема: Выполнение запросов к базе данных в фоновом потоке
Данный документ объясняет как выполнить запрос в фоновом режиме, используя класс TThread. Для получения общей информации о классе TThread, пожалуйста обратитесь к документации Borland и электронной справке. Для понимания данного документа вам необходимо иметь представление о том, как работать с компонентами для работы с базами данных, поставляемых в комплекте с Delphi 2.0.
Для осуществления потокового запроса необходимо выполнение двух требований. Во-первых, потоковый запрос должен находиться в своей собственной сессии с использованием отдельного компонента TSession. Следовательно, на вашей форме должен находиться компонент TSession, имя которого должно быть назначено свойству SessonName компонента TQuery, используемого для выполнения потокового запроса. Для каждого используемого в потоке компонента TQuery вы должны использовать отдельный компонент TSession. При использовании компонента TDataBase, для отдельного потокового запроса должен также использоваться отдельный TDataBase. Второе требование заключается в том, что компонент TQuery, используемый в потоке, не должен подключаться в контексте это потока к TDataSource. Это должно быть сделано в контексте первичного потока.
Приведенный ниже пример кода иллюстрирует описываемый процесс. Данный модуль демонстрирует форму, которая содержит по два экземпляра следующих компонентов: TSession, TDatabase, TQuery, TDataSource и TDBGrid. Данные компоненты имеют следующие значения свойств:
Query2 DataBaseName "DB2" SessionName "Ses2" SQL.Strings "Select * from customer"
DataSource2 DataSet ""
DBGrid1 DataSource DataSource2 Обратите внимание на то, что свойство DataSet обоих компонентов TDataSource первоначально никуда не ссылается. Оно устанавливается во время выполнения приложения, и это проиллюстрировано в коде.
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;