IBquery在执行查询时冻结主窗体 - 如何防止冻结?

Yor*_*iev 2 delphi firebird

我在其中一个表单上有一个TIBquery对象,执行繁重的查询,表单冻结了一段时间.

  • 可以防止这种"冻结",以及如何?

Hei*_*cht 8

数据库查询阻止了您的UI线程.使用后台线程进行查询.这里这里已经涵盖类似的主题.


你问了一个例子,所以这里有一个.请注意,代码是伪的,因为它适用于普通TQuery,跳过所有设置,拆除,错误检查并直接包含在主窗体的单元中.它只是说明了解决问题的一种方法.

  //  Create a descendant of TThread. This thread will execute your query
  //  asynchronously.
  TMyQueryThread = class(TThread)
  private
    FQueryString: string;
    FMyQuery: TQuery;
  protected
    procedure Execute; override;
  public
    constructor Create(QueryString: string);
    destructor Destroy; override;
    property MyQuery: TQuery read FMyQuery;
  end;

//  This processes the query result. Do whatever you need to do with the data,
//  but remember to do it quick. Otherwise you will freeze your UI again.
procedure ProcessResult(Data: TDataSet);
begin
  // process the data
  while not Data.Eof do
    Data.Next;
end;

//  This will be called when the thread terminates. 
//
//  Context: The code in here is executed in the main thread.
procedure TForm1.HandleThreadTerminate(Sender: TObject);
var
  SourceThread: TMyQueryThread;
begin
  SourceThread:= TMyQueryThread(Sender);
  // invoke data processing
  ProcessResult(SourceThread.MyQuery);
end;

//  When the user decides to run the query we create our thread. This call 
//  will take minimal time, so it doesn't block the UI.
//
//  Context: The code in here is executed in the main thread.
procedure TForm1.Button1Click(Sender: TObject);
begin
  with TMyQueryThread.Create('SELECT * FROM Table') do
  begin
    // we want to know when the thread finished its work so register for the event
    OnTerminate := HandleThreadTerminate;
    // this will free the thread object after OnTerminate has been called
    FreeOnTerminate := True;
  end;
end;

{ TMyQueryThread }

//  Constructor of the thread class. This takes the sql string to be executed.
//
//  Context: In this example, the code in here is executed in the main thread.
constructor TMyQueryThread.Create(QueryString: string);
begin
  // don't forget to call inherited constructor; tell it to start running immediately
  inherited Create(False);
  // save query string
  FQueryString := QueryString;
end;

//  Do the work which used to freeze your UI.
//
//  Context: The code in here does NOT run in the main thread.
procedure TMyQueryThread.Execute;
begin
  // mock query - this is your TIBQuery
  FMyQuery:= TQuery.Create(nil);
  with FMyQuery do
  begin
    SQL.Text:= FQueryString;
    // this will take a while but it doesn't matter because it only blocks the current thread, not the main thread
    Open;
  end;
end;

destructor TMyQueryThread.Destroy;
begin
  FMyQuery.Free;
  inherited;
end;
Run Code Online (Sandbox Code Playgroud)

这适用于我使用的数据库组件.注意不要在中执行任何与UI相关的活动Execute.代码TQuery在主线程和查询线程之间共享.您可能不仅需要在线程内创建查询,还需要在数据库连接中创建查询.您应该在每个查询数据库的线程中使用一个连接.