【转】Delphi多线程学习(9):多线程数据库查询(ADO)

原文:http://www.cnblogs.com/djcsch2001/articles/2382559.html

ADO多线程数据库查询通常会出现3个问题:

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中。

  {主窗体代码}  

  1. unit Main;  
  2.    
  3. interface  
  4.    
  5. uses  
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7.   Dialogs, DB, ADODB, StdCtrls;  
  8.    
  9. type  
  10.   TForm2 = class(TForm)  
  11.     ComboBox1: TComboBox;  
  12.     ComboBox2: TComboBox;  
  13.     ComboBox3: TComboBox;  
  14.     ListBox1: TListBox;  
  15.     ListBox2: TListBox;  
  16.     ListBox3: TListBox;  
  17.     Button1: TButton;  
  18.     ADOConnection1: TADOConnection;  
  19.     ADOQuery1: TADOQuery;  
  20.     Label1: TLabel;  
  21.     Label2: TLabel;  
  22.     Label3: TLabel;  
  23.     procedure FormCreate(Sender: TObject);  
  24.     procedure Button1Click(Sender: TObject);  
  25.   private  
  26.     { Private declarations }  
  27.   public  
  28.     { Public declarations }  
  29.   end;  
  30.    
  31. var  
  32.   Form2: TForm2;  
  33.    
  34. implementation  
  35.    
  36. uses ADOThread;  
  37.    
  38. {$R *.dfm}  
  39.    
  40. procedure TForm2.Button1Click(Sender: TObject);  
  41. const  
  42.   SQL_CONST='Select SaleDate from orders where CustNo = %d';  
  43. var  
  44.   c1,c2,c3:Integer;  
  45.   s1,s2,s3:string;  
  46. begin  
  47.   //取得三个选择框客户的编码   
  48.   c1:=Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]);  
  49.   c2:=Integer(ComboBox2.Items.Objects[ComboBox2.ItemIndex]);  
  50.   c3:=Integer(ComboBox3.Items.Objects[ComboBox3.ItemIndex]);  
  51.   //生成SQL 查询语句   
  52.   s1:=Format(SQL_CONST,[c1]);  
  53.   s2:=Format(SQL_CONST,[c2]);  
  54.   s3:=Format(SQL_CONST,[c3]);  
  55.   //三个线程同时查询   
  56.   TADOThread.Create(s1,ListBox1,Label1);  
  57.   TADOThread.Create(s2,ListBox2,Label2);  
  58.   TADOThread.Create(s3,ListBox3,Label3);  
  59. end;  
  60.    
  61. procedure TForm2.FormCreate(Sender: TObject);  
  62. var  
  63.   strSQL:string;  
  64. begin  
  65.   strSQL:='SELECT CustNo,Company FROM customer';  
  66.   ADOQuery1.Close;  
  67.   ADOQuery1.SQL.Clear;  
  68.   ADOQuery1.SQL.Add(strSQL);  
  69.   ADOQuery1.Open;  
  70.   ComboBox1.Clear;  
  71.   ComboBox2.Clear;  
  72.   ComboBox3.Clear;  
  73.   //将客户Company和相关CustNo填到ComboBox中   
  74.   while not ADOQuery1.Eof do  
  75.   begin  
  76.     ComboBox1.AddItem(ADOQuery1.Fields[1].asString,  
  77.         TObject(ADOQuery1.Fields[0].AsInteger));  
  78.     ADOQuery1.Next;  
  79.   end;  
  80.   ComboBox2.Items.Assign(ComboBox1.Items);  
  81.   ComboBox3.Items.Assign(ComboBox1.Items);  
  82.   // 默认选中第一个   
  83.   ComboBox1.ItemIndex := 0;  
  84.   ComboBox2.ItemIndex := 0;  
  85.   ComboBox3.ItemIndex := 0;  
  86. end;  
  87.    
  88. end.{ADO查询多线程单元}  
  89. unit ADOThread;  
  90.    
  91. interface  
  92.    
  93. uses  
  94.   Classes,StdCtrls,ADODB;  
  95.    
  96. type  
  97.   TADOThread = class(TThread)  
  98.   private  
  99.     { Private declarations }  
  100.     FListBox:TListBox;  
  101.     FLabel:TLabel;  
  102.     ConnString:WideString;  
  103.     FSQLString:string;  
  104.     procedure UpdateCount;  
  105.   protected  
  106.     procedure Execute; override;  
  107.   public  
  108.     constructor Create(SQL:string;LB:TListBox;Lab:TLabel);  
  109.   end;  
  110.    
  111. implementation  
  112.    
  113. uses Main,SysUtils,ActiveX;  
  114.    
  115. { TADOThread }  
  116.    
  117. constructor TADOThread.Create(SQL: string; LB: TListBox;Lab:TLabel);  
  118. begin  
  119.   ConnString:=Form2.ADOConnection1.ConnectionString;  
  120.   FListBox:=LB;  
  121.   FLabel:=Lab;  
  122.   FSQLString:=SQL;  
  123.   Inherited Create(False);  
  124. end;  
  125.    
  126. procedure TADOThread.Execute;  
  127. var  
  128.   Qry:TADOQuery;  
  129.   i:Integer;  
  130. begin  
  131.   { Place thread code here }  
  132.   FreeOnTerminate:=True;  
  133.   CoInitialize(nil);  //必须调用(需Uses ActiveX)   
  134.   Qry:=TADOQuery.Create(nil);  
  135.   try  
  136.     Qry.ConnectionString:=ConnString;   //必须有自己的连接   
  137.     Qry.Close;  
  138.     Qry.SQL.Clear;  
  139.     Qry.SQL.Add(FSQLString);  
  140.     Qry.Open;  
  141.     FListBox.Clear;  
  142.     for i := to 100 do  //为了执行久点重复历遍数据集101次   
  143.       begin  
  144.         while not Qry.Eof And not Terminated do  
  145.         begin  
  146.           FListBox.AddItem(Qry.Fields[0].asstring,nil);  
  147.           //如果不调用Synchronize,会出现Canvas Does NOT Allow Drawing   
  148.           Synchronize(UpdateCount);  
  149.           Qry.Next;  
  150.         end;  
  151.         Qry.First;  
  152.         FListBox.AddItem('*******',nil);  
  153.       end;  
  154.   finally  
  155.     Qry.Free;  
  156.   end;  
  157.   CoUninitialize;  
  158. end;  
  159.    
  160. procedure TADOThread.UpdateCount;  
  161. begin  
  162.   FLabel.Caption:=IntToStr(FListBox.Items.Count);  
  163. end;  
  164.    
  165. end.  

程序运行结果如下:

可以看到三个线程同时执行。第一第三两个线程条件一样,查询的结果也一样。

原文地址:https://www.cnblogs.com/tc310/p/4838301.html