在开发两层数据库软件时,因为网络慢,数据库查询时会出现界面假死情况,想把查询放到线程里面,这样就不会有影响界面的问题了,但是查询得到的记录集如何传递给datagrid之类的控件没有好的办法,请支招。线程数据库

解决方案 »

  1.   

    1、分页查询,避免一次查询大量数据
    2、使用内存数据集,诸如ClientDataSet,多线程获取数据后追加至ClientDataSet,注意线程互斥保护
      

  2.   

    給你一個示例:
    1.主程序單元:
    unit TestThreadMainForm;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Grids, DBGrids, DB, ADODB,TQueryThreadUnit, ComCtrls,
      DBGridEh, DBGridEhGrouping, GridsEh;type
      TForm1 = class(TForm)
        ADODataSet1: TADODataSet;
        DataSource1: TDataSource;
        Button1: TButton;
        StatusBar1: TStatusBar;
        DBGridEh1: TDBGridEh;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        procedure ThreadTerminate(Sender :TObject);
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      MyQueryThread :TQueryThread;
    begin  //CoInitialize(nil);
      try
      MyQueryThread :=TQueryThread.Create(ADODataset1,DataSource1,StatusBar1);
      MyQueryThread.OnTerminate := ThreadTerminate;
      MyQueryThread.Resume;
      StatusBar1.SimpleText := '請等待,正在打開數據表......';
      StatusBar1.SimplePanel := True;
      finally
       //CoUninitialize;
      end;
      //ADODataSet1.Open;
    end;procedure TForm1.ThreadTerminate(Sender:TObject);
    begin
      ShowMessage('線程終止顯示!');
    end;
    end.
    2.線程查詢單元:
    unit TQueryThreadUnit;interfaceuses
      Classes,ADODB,DB,ActiveX,ComCtrls;type
      TQueryThread = class(TThread)
      private
        FDataSet :TADODataSet;
        FDataSource :TDataSource;
        FStatusBar :TStatusBar;
        procedure HookUpUI;
        { Private declarations }
      protected
        procedure Execute; override;
      public
        constructor Create(ADataSet:TADODataSet;ADataSource:TDataSource;AStatusBar:TStatusBar);virtual;
      end;implementation{ Important: Methods and properties of objects in visual components can only be
      used in a method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure TQueryThread.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ TQueryThread }
    constructor TQueryThread.Create(ADataSet:TADODataSet;ADataSource:TDataSource;AStatusBar:TStatusBar);
    begin
      inherited Create(True);
      FDataSet := ADataSet;
      FDataSource := ADataSource;
      FStatusBar := AStatusBar;
      FreeOnTerminate := True;
      //Resume;
    end;procedure TQueryThread.Execute;
    begin
      { Place thread code here }
      CoInitialize(nil);
      try
        if not FDataSet.Active then FDataSet.Open;
        Synchronize(HookUpUI);
      finally
       CoUninitialize;
      end;
    end;procedure TQueryThread.HookUpUI;
    begin
      FDataSource.DataSet := FDataSet;
      FStatusBar.SimpleText := '已經打開數據表!';
    end;
    end.
      

  3.   

    感谢kv2002、Oraclers、liangpei2008,不管怎么分页,在查询时还是会对界面造成影响,我们不能保证网络状态一直都是很好,所以保障客户感受还是想将查询线程和绘制界面的主线程分离,谢谢Oraclers的代码。我试试zeos的配合效果
      

  4.   

    比较好的办法是用uniDAC+ClientDataSetuniDAC可以查询到一部分先显示一部分,然后写到内存表,逐步显示;用ADO查询必须查询完成才显示就比较慢了。
      

  5.   

    TClientDataSet足矣,其Data属性就是取到的值。
    一般的做法是通过Provider从数据库读取数据,将结果赋给TClientDataSet.Data,这样,与TClientDataSet连接的感知控件就能显示结果了。
    由于通过Provider取数和将结果赋给TClientDataSet完全可以分到不同的线程中处理,所以,实现你的需求没啥问题