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

程序运行结果如下:

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

【转】Delphi多线程学习(9):多线程数据库查询(ADO)的更多相关文章

  1. C#多线程学习(一) 多线程的相关概念(转)

    什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...

  2. C#多线程学习(一) 多线程的相关概念

    什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...

  3. [转载]C#多线程学习(一) 多线程的相关概念

    原文地址:http://www.cnblogs.com/xugang/archive/2008/04/06/1138856.html 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的 ...

  4. C#多线程学习(四) 多线程的自动管理(线程池)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  5. MySQL学习基础之一 — 数据库查询

    廖大神的练手神器:在线SQL: https://www.liaoxuefeng.com/wiki/1177760294764384/1179611432985088 运行MySQL等实际的数据库软件, ...

  6. Java学习笔记 DbUtils数据库查询和log4j日志输出 使用

    DbUtils使用 QueryRunner DbUtils中定义了一个数据库操作类QueryRunner,所有的数据库操作CRUD都是通过此类来完成. 此类是线程安全的 方法名 对应sql语句 exc ...

  7. C++并发与多线程学习笔记--多线程数据共享问题

    创建和等待多个线程 数据和共享问题分析 只读的数据 有读有写 其他案例 共享数据的保护案例代码 创建和等待多个线程 服务端后台开发就需要多个线程执行不同的任务.不同的线程执行不同任务,并返回执行结果. ...

  8. 学习练习 java数据库查询小题

    10. 查询Score表中的最高分的学生学号和课程号.(子查询或者排序) 11. 查询每门课的平均成绩. 12.查询Score表中至少有5名学生选修的并以3开头的课程的平均分数. 13.查询分数大于7 ...

  9. C#多线程学习(五) 多线程的自动管理(定时器)

    Timer类:设置一个定时器,定时执行用户指定的函数.               定时器启动后,系统将自动建立一个新的线程,执行用户指定的函数. 初始化一个Timer对象:  Timer timer ...

  10. 【转】C#多线程学习

    C#多线程学习(一) 多线程的相关概念 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序 ...

随机推荐

  1. Cocos2d-android (03) 向量

    向量的基本运算及动作 import org.cocos2d.actions.interval.CCJumpBy; import org.cocos2d.actions.interval.CCMoveB ...

  2. 八皇后问题 --- 递归解法 --- java代码

    八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行.纵行或斜线上.八皇后 ...

  3. 记一个社交APP的开发过程——基础架构选型(转自一位大哥)

    记一个社交APP的开发过程——基础架构选型 目录[-] 基本产品形态 技术选型 最近两周在忙于开发一个社交App,因为之前做过一点儿社交方面的东西,就被拉去做API后端了,一个人头一次完整的去搭这么一 ...

  4. memset()实现及细节

    memset是计算机中C/C++语言函数.将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值, 块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为 ...

  5. iOS 获取通讯录权限的时机

    建议将获取通讯录权限的代码放到 -(void)viewDidAppear:(BOOL)animated 或 -(void)viewWillAppear:(BOOL)animated 假如放在 view ...

  6. 邮件发送服务AWS SES,Mailgun以及SendCloud(转)

    原文:http://www.l4zy.com/posts/aws_ses-mailgun-sendcloud.html 电子邮件这一已经诞生很多年的互联网基础服务并没有随着时间的推移而慢慢消亡,实际上 ...

  7. xcode报错:Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/b

    今天使用xcode编译工程发现一个问题,这里记录一下防止忘记 xcode报错: Command /Applications/Xcode.app/Contents/Developer/Toolchain ...

  8. 错误提示:类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内 .

    错误提示:类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内 在做导出数据到EXCEL程序中,出现了错误提示:类型“GridView”的控件“Gr ...

  9. MYSQL数据库性能调优之七:其他(读写分离、分表等)

    一.分表 水平划分 垂直划分 二.读写分离 三.选择合理的数据类型 特别是主键 四.文件.图片等大文件使用文件系统存储 五.数据库参数配置 注意:max_connections最大连接数一般设置在10 ...

  10. 修改hosts文件解决OneDrive被墙的问题

    增加如下内容就可以了.如果不知道修改hosts文件的具体方法请自行百度. 134.170.108.26 onedrive.live.com 134.170.108.152 skyapi.onedriv ...