关于ADO线程查询显示问题(50分)

  • 主题发起人 主题发起人 liangexcel
  • 开始时间 开始时间
L

liangexcel

Unregistered / Unconfirmed
GUEST, unregistred user!
因为一次性查询太多的表,滞后时间太长,很多人都说要用线程才能解决问题.
我用的是ADO,也有很多人说用ADO线程不安全,要将主线程的ADO和线程内的ADO要分离.
我将ADO连接字符串,SQL字符串传入线程,在线程内创建ADOCONNECTION,用连接字符串进行连接,创建ADOQUERY进行查询,但如何将这个查询结果送到主线程显示出来?(线程结束,线程内创建的ADOCONNECTION和ADOQUERY已经被释放)
 
1. 你的问题不在线程上面;
2. 查询太多的表必定要太多的时间, 线程解决不了的;
3. 设计数据库(表)的时候做好索引, 这样能提高查询速度;
4. 一定要用线程, 可以将connection和query放在外面(全局变量)也是可以的;
 
to 新世纪:
1.我现在的问题是如何把在线程内查询的结果显示到主线程上.
2.我是在窗口创建时查询,我不想我的程序滞后停留太多时间,所以一边创建窗体,一边查询.窗体不用等查询有结果时才显示.
3.我的不是查询速度问题,是滞后的问题
 
如果要做线程就要做彻底!
如果能用线程查询数据当然好了!
由于你使用的是ADO,所以建议你可以在你的线程类里公布一个属性
TYourADOThread = class(TThread)
public
property QueryData: _Recordset read GetQueryData;
end;
GetQueryData的实现和简单: Result := ADOQuery1.Recordset;
///////////////////////
在主线程中,也创建一个TADODataSet,
在线程终止之前,将线程的QueryData赋值给ADODataSet的RecordSet属性。
下面是测试代码:
//////.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, ADODB, StdCtrls, Grids, DBGrids;
type
TADOThread = class(TThread)
private
FQuery: TADOQuery;
FConnection: TADOConnection;
function GetQueryData: _Recordset;
protected
procedure Execute;
override;
public
constructor Create(AConnStr, ASQL: string);
destructor Destroy;
override;
property QueryData: _Recordset read GetQueryData;
end;

TForm1 = class(TForm)
ADODataSet1: TADODataSet;
Button1: TButton;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
ADOConnection1: TADOConnection;
procedure Button1Click(Sender: TObject);
private
FThread: TADOThread;
proceduredo
OnThreadEnd(Sender: TObject);
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation
uses
ActiveX;
{$R *.dfm}
{ TADOThread }
constructor TADOThread.Create(AConnStr, ASQL: string);
begin
inherited Create(True);
CoInitialize(nil);
FQuery := TADOQuery.Create(nil);
FConnection := TADOConnection.Create(nil);
FQuery.Connection := FConnection;
FConnection.ConnectionString := AConnStr;
FConnection.LoginPrompt := False;
FQuery.SQL.Text := ASQL;
end;

destructor TADOThread.Destroy;
begin
FQuery.Free;
FConnection.Free;
inherited;
end;

procedure TADOThread.Execute;
begin
FConnection.Connected := True;
FQuery.Open;
end;

function TADOThread.GetQueryData: _Recordset;
begin
Result := FQuery.Recordset;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
FThread := TADOThread.Create(ADOConnection1.ConnectionString, 'Select * from a');
FThread.OnTerminate :=do
OnThreadend;
FThread.Resume;
end;

procedure TForm1.DoOnThreadEnd(Sender: TObject);
begin
ADODataSet1.Recordset := TADOThread(Sender).QueryData;
end;

end.
////////////////////////////// .dfm
object Form1: TForm1
Left = 209
Top = 199
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 240
Top = 64
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object DBGrid1: TDBGrid
Left = 40
Top = 120
Width = 505
Height = 209
DataSource = DataSource1
TabOrder = 1
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
end
object ADODataSet1: TADODataSet
Parameters = <>
Left = 168
Top = 64
end
object DataSource1: TDataSource
DataSet = ADODataSet1
Left = 136
Top = 64
end
object ADOConnection1: TADOConnection
ConnectionString =
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=H:/data/Mydo
cument' +
's/db1.mdb;Persist Security Info=False'
Mode = cmShareDenyNone
Provider = 'Microsoft.Jet.OLEDB.4.0'
Left = 208
Top = 64
end
end
 
原理上应该可以说过去,因为_RecordSet是由ADO组件创建的,不在线程空间中,因此线程释放不会引起其释放。
 
to xiammy:跟我以前实现的完全不同,谢谢.我现在就试用一下.
 
TO xiammy:你的方法线程并不释放.我在释构函数中加了一个事件,事件并不执行.
destructor THQuery.Destroy;
begin
FQuery.Free;
FConnection.Free;
synchronize(showtext);
CoUnInitialize;
inherited;
end;
但是数据可以查询,移动浏览数据没有问题.
我在构造函数里面加了一句
FreeOnTerminate := true;
释构函数里的showtext事件执行,但是移动浏览数据里就出错,&quot;对象已经关闭&quot;.我想是因为_RecordSet跟随着线程内创建的ADO控件释放而释放了.
 
1。synchronize(showtext);
应该放在线程的execute里,且在查询出结果后
2。你可以在线程里把查询结果组合成XML或其他格式,然后向主线程发送消息。
PostMessage(frmMain.Handle,WM_SHOW_XML,pchar(strXml),0);
然后在主线程窗口里处理WM_SHOW_XML事件进行解析。
 
to risingsoft:
1.我知道synchronize应该放在execute,我放在释构上是因为我不知道如何得知道线程是否被释放,结果似乎可行.至少我知道释构函数被执行与否.
showtext事件只是一个Shwomessage('Yes')事件,我是用来得知释构是否被执行,不是用于显示结果.
2.其实我也可以把线程中查得的结果用循环的方式,把结果写入GRID,但现在我只是想测试ADO的.这个问题的确让我懊恼了很久.....
 
其实你是不是可以考虑在线程外创建的ADOCONNECTION和ADOQUERY 然后把ADOQUERY传送进线程,在线程中慢慢打开,完成后发送消息到主线程,主线程再进行处理
 
to hellbeast:我现在是方式是在外部创建ADOCONNECTION,ADOQUERY,然后把他们传入线程内,线程内再创建一个ADOQUERY,线程内的CONNECTION使用是传入的ADOCONNECTION,查询完成后,把线程内的ADOQUERY复制给传入的ADOQUERY.需要可以运行,但总担心一个ADO安全问题,虽然现在还没有出问题,所以我想找一点别人用线程ADO的思路,看看和我的有何不同.
 
function TADOThread.GetQueryData: _Recordset;
begin
Result := FQuery.Recordset;
end;

这里要用这样
function TADOThread.GetQueryData: _Recordset;
var
rec:_Recordset;
begin
rec.assign( FQuery.Recordset);
end;

或者
procedure TForm1.DoOnThreadEnd(Sender: TObject);
begin
ADODataSet1.Recordset.assign(TADOThread(Sender).QueryData);
end;

否则 都只是数据指针指向一个地方
 
我现在写的一个程序是:
1.一个查询包括参数输入,显示打印,和他们的界面整个作为一个project.
2.每个projecet一个线程.
3,在打开一个project的SQL查询时,这个project的界面也会停止,但不影响你打开另一个project,同一个project你可以同时开几个.
这是我看见别人用我的程序时,在等一个查询时,他们回开第2第3个进程后想到的
 
多线程查询不一定比主线程查询快,有时甚至更慢.我试了,但是不适用.我决定把原来综合在一个窗口的多个查询分散一个窗体一个查询,因为一次性根本就看不了那么多的内容.把需要看的查询,不需要的先留着.
 
不知道 LZ有没有试过把ADO设为异步模式
 
放弃多线程查询,因为效率并没有提高
 
后退
顶部