Многопоточный доступ к базам данных ADO в Delphi
Данная статья претендует лишь на то, чтобы хоть как-то скрыть пробел в данном вопросе. Многопоточному доступу к базам данных ADO уделено очень мало внимания, то ли из-за того, что реализовать его не так уж и сложно, то ли из-за того, что тема не так уж и акутальна.
Для наглядности сформулируем и выполним следующую задачу.
Создадим 12 потоков доступа к базе данных ADO типа Access, и в каждом потоке добавим по 100 записей. Потоки программируем используя класс TThread. Создадим базу данных thread.mdb c одной таблицей «Example». Таблица будет содержать три текстовых поля с именами: N, AddTime, NumItem. В поле N будем заносить номер потока, из которого будет добавляться запись, во втором поле будет содержаться время добавления записи в таблицу, а в третье будет заносится порядковый номер добавляемой записи.
На форму добавим только кнопку TButton и больше никаких визуальных компоненты нам не понадобится. Реализация задачи будет выглядеть так:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, ADODB, StdCtrls, DBTables;
type
TPotok = class(TThread)
private
Cnt:integer;
protected
procedure Execute; override;
public
constructor Create(i:integer);
end;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
Potoks: array [1..12] of TPotok;
n:integer;
procedure TForm1.Button1Click(Sender: TObject);
begin
for n:=1 to 12 do
Potoks[n]:=TPotok.Create(n);
end;
constructor TPotok.Create(i:integer);
begin
Cnt:=i;
inherited Create(False);
FreeOnTerminate:=True;
end;
procedure TPotok.Execute;
var
Q:TADOQuery;
t:integer;
begin
Q:=TADOQuery.Create(Application);
Q.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\thread.mdb;Persist Security Info=False;Jet OLEDB:Database Password=""'; //(1)
for t:=1 to 100 do
begin
Q.Close;
Q.SQL.Clear;
Q.SQL.Add('INSERT INTO Example (N,AddTime,NumItem) VALUES ("'+IntToStr(Cnt)+'","'+DateTimeToStr(Now)+'","'+IntToStr(t)+'")');
Q.ExecSQL; //(2)
end;
Q.Free;
end;
end.
В секцию uses проекта нужно добавить модуль ComObj, а перед инициализацией приложения нужно добавить строку инициализации COM-объекта, коим является используемый нами TADOQuery
program Project1;
uses
Forms,ComObj,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
CoInitFlags := 0;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
В нашем примере объект TADOQuery создаётся динамически и подключение к источнику данных реализуется присваиванием значению свойства ConnectionString объекта строки настроек(1).
SQL запрос исполняется методом ExecSQL, а не обычным Open, т.к. результирующий набор данных нам не возвращается – мы просто добавляем записи в таблицу.
Ещё можно обратить внимание на то, что в поток мы передаём переменную i целого типа, которая хранит в потоке его порядковый номер.
Проверить работу нашего примера после нажатия на кнопку в скомпилированном приложении можно открыв таблицу Microsoft Access, после чего убеждаемся в том, что все наши 1200 записей в ходе работы приложения были добавлены в таблицу Example.
Исходник примера и база данных thread.mdb здесь. |