为什么我在线程的Execute过程中涉及到的数据库操作总是不能执行(100分)

  • 主题发起人 主题发起人 aocandy
  • 开始时间 开始时间
A

aocandy

Unregistered / Unconfirmed
GUEST, unregistred user!
unit mst;
interface
uses
SysUtils, Classes,Dialogs;
type
st = class(TThread)
private
{ Private declarations }
protected
procedure Execute;
override;
end;
implementation
uses m;
{ st }
procedure st.Execute;
var i:integer;
begin
i:=1;
While Truedo
begin
Form1.Label1.Caption:=IntToStr(i)+'4'+Form1.ADOTable1['name'];
////这里的问题
inc(i);
end;
end;
end.
如果把上面的那句换成Form1.Label1.Caption:=IntToStr(i);则运行正常,ADOTable1已经在
打开线程的form中打开了~在delphi的编辑环境下运行此程序~提示说找不到name字段,可是数据库
里面明明有阿
 
Form1.Label1.Caption:=IntToStr(i)+'4'+Form1.ADOTable1['name'];
我没看过这种用法,你试试改为:
Form1.Label1.Caption:=IntToStr(i)+'4'+Form1.ADOTable1.FieldByName('name').AsString;
 
不行,同样 的错误
 
你声明一个线程内的Table,不要直接引用 Form1.table
试一下!
 
你这样写线程简直太恐怖了!
涉及到不安全的操作都要使用同步的方法!
最好在线程内动态创建需要的东西,更新Form1.Label1.Caption的时候要使用主线程来同步
Synchronize(UpdateLabel1);
procedure TMyThread.UpdateLable1;
begin
Form1.Label1.Caption := '交给主线程才是安全的';
end;
 
Synchronize(UpdateLabel1);//这个是干吗的
procedure TMyThread.UpdateLable1;//这个怎么用阿
begin
Form1.Label1.Caption := '交给主线程才是安全的';
end
 
unit mst;
interface
uses
SysUtils, Classes,Dialogs,ADODB;
type
st = class(TThread)
ADOT:TADOTable;
private
{ Private declarations }
protected
procedure Execute;
override;
end;

implementation
uses m;
{ st }
procedure st.Execute;
var i:integer;
begin
ADOT.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:/netdb200210.mdb;';
ADOT.TableName:='peo';
try
ADOT.Close;
ADOT.Open;
ShowMessage('dd33');
except
ShowMessage('dd');
ADOT.Close;
ADOT.Free;
end;
i:=1;
While Truedo
begin
Form1.Label1.Caption:=IntToStr(i)+'4';//+Form1.ADOTable1.FieldByName('name').AsString;
inc(i);
end;

end;

end.
这样仍然不行
 
unit mst;
interface
uses
SysUtils, Classes,Dialogs,ADODB;
type
st = class(TThread)
ADOT:TADOTable;
private
{ Private declarations }
protected
procedure Execute;
override;
end;

implementation
uses m;
{ st }
procedure st.Execute;
var i:integer;
begin
ADOT.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:/netdb200210.mdb;';
ADOT.TableName:='peo';
try
ADOT.Close;
ADOT.Open;
ShowMessage('dd33');
except
ShowMessage('dd');
ADOT.Close;
ADOT.Free;
end;
i:=1;
While Truedo
begin
Synchronize(kk);
inc(i);
end;
end;
procedure st.kk;
begin
Form1.Caption := Form1.Table1.FieldByName('Name').AsString;
end;

end.

改成这样就ok了
个人观点
Caption 在子线程内部改动,应该让父线程有时间来修改界面

 
上边的这个回复在我编译时提示错误了
Undeclared identifier 'kk'
 
type
st = class(TThread)
ADOT:TADOTable;
private
{ Private declarations }
procedure kk;
protected
procedure Execute;
override;
end;
 
我靠,你真有够愚的
 
我愚,是~~你也是试试你说的能不能执行嗄~~以上所有人说的结果都不能用阿~~
 

--------------------------------------------------------------------------------
优秀的数据库应用应当充分考虑数据库访问的速度问题。通常可以通过优化数据库、优化 查询语句、分页查询等途径收到明显的效果。即使是这样,也不可避免地会在查询时闪现一个带有 SQL符号的沙漏,即鼠标变成了查询等待。最可怜的是用户,他(她)在此时只能无奈地等待。遇到急性子的,干脆在此时尝试 Windows中的其它应用程序,结果致使你的数据库应用显示一大片白色的窗口。真是无奈!
本文将以简单的例子告诉你如何实现线程查询。还等什么,赶快打开Delphi对照着下面的完整源代码试试吧。
在查询时能够做别的事情或者取消查询,这只是基本的线程查询,在你阅读了Delphi有关线程帮助之后能立刻实现。这里介绍的是多个线程查询的同步进行。
在Delphi数据库应用中,都有一个缺省的数据库会话 Session。通常情况下,每个数据库应用中只有这一个会话。无论是查询函数修改数据,在同一时间内只能进行其中的一件事情, 而且进行这一件事情的时候应用程序不能响应键盘、鼠标以及其它的 Windows消息。这就是在 窗口区域会显示一片空白的原因所在。当然,只要将查询或数据操纵构造成线程对象,情况会好一些,至少可以接受窗口消息,也可以随时终止查询或数据操纵,而不会在屏幕上显示出太难看的白色。不过,这只是解决了问题的一部分。假如在进行一个线程查询的时候,用户通过 按钮或菜单又发出了另一个查询的命令,这可如何是好,难道终止正在执行的数据库访问吗? 解决之道就是:多线程同步查询。
实现多线程同步查询的基本思想是,为每一个查询组件(如TQuery组件)创建一个独占的 数据库会话,然后各自进行数据库访问。需要特别注意的是,因为Delphi中的 VCL组件大多都 不是线程安全的,所以应当在线程查询结束后再将DataSource组件与查询组件关联,从而显示 在DBGrid组件中。
下面的例子只实现了静态的线程同步查询,即线程对象是固定的,并随窗体的创建和销毁 而创建和销毁。你可以就此进行改进,为每一个数据查询或数据操纵命令创建一个单独的线程对象,从而达到多线程同步查询的目的。
注意:应用程序中的线程不是越多越好,因为线程将严重吞噬CPU资源,尽管看上去并不明显。谨慎创建和销毁线程将避免你的应用程序导致系统资源崩溃。
下面的例子给出了同时进行的两个线程查询。第一次按下按钮时,线程开始执行;以后每次按下按钮时,如果线程处于挂起状态则继续执行,否则挂起线程;线程执行完毕之后将连接 DataSource,查询结果将显示在相应的DBGrid中。
{ 这里的多线程同步查询演示程序仅包括一个工程文件和一个单元文件 }
{ 窗体中放置的组件有: }
{ 两个Session组件 }
{ 两个Database组件 }
{ 两个Query组件 }
{ 两个DataSource组件 }
{ 两个DBGrid组件 }
{ 一个Button组件 }
{ 除非特别说明,否则上述各组件的属性都取默认值(见各组件注释) }
{ 对于Database组件,就和一般设置一样,有一个正确的连接即可 }
{ 对于Query 组件,需要在各自的属性 SQL中添加一些查询语句,为了 }
{ 看得更清除,建议不要在两个Query 组件中填写相同的查询语句。 }
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, DBTables, Grids, DBGrids, StdCtrls;
type
TForm1 = class(TForm)
Session1: TSession;
{ 属性SessionName填写为S1 }
Database1: TDatabase;
{ 属性SessionName选择为S1 }
Query1: TQuery;{ 属性Database选择为Database1;属性SessionName选择为S1 }
DataSource1: TDataSource;
{ 属性DataSet设置为空 }
DBGrid1: TDBGrid;
{ 属性DataSource选择为DataSource1 }
Session2: TSession;
{ 属性SessionName填写为S2 }
Database2: TDatabase;
{ 属性SessionName选择为S2 }
Query2: TQuery;{ 属性Database选择为Database2;属性SessionName选择为S2 }
DataSource2: TDataSource;
{ 属性DataSet设置为空 }
DBGrid2: TDBGrid;
{ 属性DataSource选择为DataSource2 }
BtnGoPause: TButton;
{ 用于执行和挂起线程 }
procedure FormCreate(Sender: TObject);
{ 创建窗体时创建线程对象 }
procedure FormDestroy(Sender: TObject);
{ 销毁窗体时销毁线程对象 }
procedure BtnGoPauseClick(Sender: TObject);
{ 执行线程和挂起线程 }
private
public
end;

TThreadQuery = class(TThread) { 声明线程类 }
private
FQuery: TQuery;
{ 线程中的查询组件 }
FDataSource: TDataSource;
{ 与查询组件相关的数据感知组件 }
procedure ConnectDataSource;{ 连接数据查询组件和数据感知组件的方法 }
protected
procedure Execute;
override;{ 执行线程的方法 }
public
constructor Create(Query: TQuery;
DataSource: TDataSource);
virtual;
{ 线程构造器 }
end;

var
Form1: TForm1;
Q1, { 线程查询对象1 }
Q2: TThreadQuery;
{ 线程查询对象2 }
implementation
{$R *.DFM}
{ TThreadQuery类的实现 }
{ 连接数据查询组件和数据感知组件}
procedure TThreadQuery.ConnectDataSource;
begin
FDataSource.DataSet := FQuery;{ 该方法在查询结束后才调用 }
end;

procedure TThreadQuery.Execute;{ 执行线程的方法 }
begin
try
FQuery.Open;
{ 打开查询 }
Synchronize(ConnectDataSource);{ 线程同步 }
except
ShowMessage('Query Error');
{ 线程异常 }
end;
end;

{ 线程查询类的构造器 }
constructor TThreadQuery.Create(Query: TQuery;
DataSource: TDataSource);
begin
FQuery := Query;
FDataSource := DataSource;
inherited Create(True);
FreeOnTerminate := False;
end;

{ 创建窗体时创建线程查询对象 }
procedure TForm1.FormCreate(Sender: TObject);
begin
Q1 := TThreadQuery.Create(Query1, DataSource1);
Q2 := TThreadQuery.Create(Query2, DataSource2);
end;

{ 销毁窗体时销毁线程查询对象 }
procedure TForm1.FormDestroy(Sender: TObject);
begin
Q1.Terminate;
{ 销毁之前终止线程执行 }
Q1.Destroy;
Q2.Terminate;
{ 销毁之前终止线程执行 }
Q2.Destroy;
end;

{ 开始线程、继续执行线程、挂起线程 }
procedure TForm1.BtnGoPauseClick(Sender: TObject);
begin
if Q1.Suspended then
Q1.Resume else
Q1.Suspend;
if Q2.Suspended then
Q2.Resume else
Q2.Suspend;
end;

end.



 
unit mst;
interface
uses
SysUtils, Classes,Dialogs,ADODB;
type
st = class(TThread)
ADOT:TADOTable;
private
{ Private declarations }
procedure kkqq;
protected
procedure Execute;
override;
end;

implementation
uses m;
{ st }
procedure st.kkqq;
begin
Form1.Label1.Caption :=Form1.Label1.Caption+'D';
end;
procedure st.Execute;
var i:integer;
begin
ShowMessage('tt');///////////////////////
i:=1;
While Truedo
begin
Form1.Label1.Caption:=IntToStr(i);
Synchronize(kkqq);
//+'4';//+Form1.ADOTable1.FieldByName('name').AsString;
inc(i);
end;
end;
end.

别的先不说~为什么加上那句ShowMessage('tt')整个程序就不正常了
 
呵!线程中不能直接对主窗体的某个Caption进行操作,应加上Synchronize关键字!
详细内容可以查看《delphi5开发人员指南》那本书关于多线程部份!
 
看来楼主是刚刚入门的。。。
多找几本书看看吧。。。
 
我也遇到了同样的问题,但我用的是ADO连接数据库的,但一直都不行
 
to:Bxch_1000
你好,为什么我在你的例子中执行对很大数据量的表的查询的时候,鼠标键盘不能响应,
而且会出现窗体一片空白的情况。请问该如何解决这个问题呢?
[?]
 
老大!!!与主窗体通信为什么不用synchronize方法
另外:如果在线程中操作数据库 将你的table动态创建:
table1:=ttable.creat(self) 把数据库复杂操作写成写成一个函数
(代码规范很重要哦)
试一下
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
734
import
I
I
回复
0
查看
588
import
I
后退
顶部