Delphi多线程数据库查询(ADO)
ADO多线程数据库查询通常会出现以下问题:
1、CoInitialize 没有调用(CoInitialize was not called);所以,在使用任何dbGo对象前,必须手 调用CoInitialize和CoUninitialize。调用CoInitialize失败会产生"CoInitialize was not called"例外。
多线程“尚未调用coinitialize” 报错
{在多线程启用执行前 在多线程启用执行后
CoInitialize(nil); CoUninitialize;}
2、画布不允许绘画(Canvas does not allow drawing);所以,必须通过Synchronize过程来通知主线程访问主窗体上的任何控件。
3、不能使用主ADO连接(Main TADoConnection cannot be used!);所以,线程中不能使用主线程中TADOConnection对象,每个线程必须创建自己的数据库连接。
Delphi2007安装后在X:\Program Files\Common Files\CodeGear Shared\Data目录下有一个dbdemos.mdb文件,用来作为测试的例子。dbdemos.mdb中的customer表保存了客户信息,orders表中保存了订单信息。
测试程序流程大致是这样的:在主窗体上放TADOConnection和TQuery控件,启动时这个TQuery从Customer表中查出客户编码CustNo和公司名称Company,放到三个Combox框中,分别在三个列表框中选定客户公司名称,按照公司名称所对应的客户代码建立三个线程同时在orders表中查询销售日期SaleDate分别填入ListBox中。
4、COM接口调用时必须有线程自己的接口。
如:在A线程建的COM接口,B线程调用时就提示“应用程序调用一个已为另一线程整理的接口”。这时只要在B线程建立自己独有的COM接口使用就可以了。
1 {主窗体代码} 2 unit Main; 3 interface 4 uses Windows, Messages, SysUtils, Variants, 5 Classes, Graphics, Controls, Forms, Dialogs, DB, ADODB, StdCtrls; 6 type 7 TForm2 = class(TForm) 8 ComboBox1: TComboBox; 9 ComboBox2: TComboBox; 10 ComboBox3: TComboBox; 11 ListBox1: TListBox; 12 ListBox2: TListBox; 13 ListBox3: TListBox; 14 Button1: TButton; 15 ADOConnection1: TADOConnection; 16 ADOQuery1: TADOQuery; 17 Label1: TLabel; 18 Label2: TLabel; 19 Label3: TLabel; 20 procedure FormCreate(Sender: TObject); 21 procedure Button1Click(Sender: TObject); 22 private { Private declarations } 23 public { Public declarations } 24 end; 25 var Form2: TForm2; 26 implementation 27 uses 28 ADOThread; 29 {$R *.dfm} 30 31 procedure TForm2.Button1Click(Sender: TObject); 32 const 33 SQL_CONST='Select SaleDate from orders where CustNo = %d'; 34 var c1,c2,c3:Integer; s1,s2,s3:string; 35 begin //取得三个选择框客户的编码 36 c1:=Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]); 37 c2:=Integer(ComboBox2.Items.Objects[ComboBox2.ItemIndex]); 38 c3:=Integer(ComboBox3.Items.Objects[ComboBox3.ItemIndex]); //生成SQL 查询语句 39 s1:=Format(SQL_CONST,[c1]); 40 s2:=Format(SQL_CONST,[c2]); 41 s3:=Format(SQL_CONST,[c3]); //三个线程同时查询 42 TADOThread.Create(s1,ListBox1,Label1); 43 TADOThread.Create(s2,ListBox2,Label2); 44 TADOThread.Create(s3,ListBox3,Label3); 45 end; 46 47 procedure TForm2.FormCreate(Sender: TObject); 48 var 49 strSQL:string; 50 begin 51 strSQL:='SELECT CustNo,Company FROM customer'; 52 ADOQuery1.Close; 53 ADOQuery1.SQL.Clear; 54 ADOQuery1.SQL.Add(strSQL); 55 ADOQuery1.Open; 56 ComboBox1.Clear; 57 ComboBox2.Clear; 58 ComboBox3.Clear; //将客户Company和相关CustNo填到ComboBox中 59 while not ADOQuery1.Eof do 60 begin 61 ComboBox1.AddItem(ADOQuery1.Fields[1].asString, TObject(ADOQuery1.Fields[0].AsInteger)); 62 ADOQuery1.Next; 63 end; 64 ComboBox2.Items.Assign(ComboBox1.Items); 65 ComboBox3.Items.Assign(ComboBox1.Items); // 默认选中第一个 66 ComboBox1.ItemIndex := 0; 67 ComboBox2.ItemIndex := 0; 68 ComboBox3.ItemIndex := 0; 69 end; 70 end.
1 {ADO查询多线程单元} 2 unit ADOThread; 3 interface 4 uses 5 Classes,StdCtrls,ADODB; 6 type TADOThread = class(TThread) 7 private { Private declarations } 8 FListBox:TListBox; 9 FLabel:TLabel; 10 ConnString:WideString; 11 FSQLString:string; 12 procedure UpdateCount; 13 protected procedure Execute; override; 14 public constructor Create(SQL:string;LB:TListBox;Lab:TLabel); 15 end; 16 17 implementation 18 uses 19 Main,SysUtils,ActiveX; 20 { TADOThread } 21 22 constructor TADOThread.Create(SQL: string; LB: TListBox;Lab:TLabel); 23 begin 24 ConnString:=Form2.ADOConnection1.ConnectionString; 25 FListBox:=LB; 26 FLabel:=Lab; 27 FSQLString:=SQL; 28 Inherited Create(False); 29 end; 30 31 procedure TADOThread.Execute; 32 var 33 Qry:TADOQuery; 34 i:Integer; 35 begin { Place thread code here } 36 FreeOnTerminate:=True; 37 CoInitialize(nil); //必须调用(需Uses ActiveX) 38 Qry:=TADOQuery.Create(nil); 39 try 40 Qry.ConnectionString:=ConnString; //必须有自己的连接 41 Qry.Close; 42 Qry.SQL.Clear; 43 Qry.SQL.Add(FSQLString); 44 Qry.Open; 45 FListBox.Clear; 46 for i := 0 to 100 do //为了执行久点重复历遍数据集101次 47 begin 48 while not Qry.Eof And not Terminated do 49 begin 50 FListBox.AddItem(Qry.Fields[0].asstring,nil); //如果不调用Synchronize,会出现Canvas Does NOT Allow Drawing 51 Synchronize(UpdateCount); 52 Qry.Next; 53 end; 54 Qry.First; 55 FListBox.AddItem('*******',nil); 56 end; 57 finally 58 Qry.Free; 59 end; 60 CoUninitialize; 61 end; 62 63 procedure TADOThread.UpdateCount; 64 begin 65 FLabel.Caption:=IntToStr(FListBox.Items.Count); 66 end; 67 end.
程序运行结果可以看到三个线程同时执行。第一第三两个线程条件一样,查询的结果也一样。