ADO多線程數據庫查詢通常會出現以下問題:
1、CoInitialize 沒有調用(CoInitialize was not called);所以,在使用任何dbGo對象前,必須手 調用CoInitialize和CoUninitialize。調用CoInitialize失敗會產生"CoInitialize was not called"例外。
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.
程序運行結果可以看到三個線程同時執行。第一第三兩個線程條件一樣,查詢的結果也一樣。