2011-11-22 90 views

回答

8

數據庫查詢阻塞了您的UI線程。爲您的查詢使用後臺線程。一個類似的話題已經涵蓋了herehere


你要求一個例子,所以這裏是一個例子。請注意,代碼是僞代碼,因爲它與普通的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; 

這適用於我使用的數據庫組件。請注意不要在Execute中進行與UI相關的任何活動。代碼在主線程和查詢線程之間共享一個TQuery。您不僅可以在線程內部創建查詢,還可以在數據庫連接中創建查詢。您應該爲每個從您查詢數據庫的每個線程使用一個連接。

+0

我不熟悉的設置IB組件集成到單獨的線程。請 - 你可以提供一些例子嗎? –

+0

殺死好榜樣!非常感謝Heinrich Ulbricht。 –

+0

還有一個問題 - 我可以自由地將數據集附加到某個表中,或者在數據可視化之前我會做其他事情嗎? –

1

您必須在後臺線程中執行您的查詢。國際海事組織更好的免費(與源)解決方案是組件TBMDThread(谷歌它)。我建議使用單獨的連接進行後臺查詢。

TBMDThread http://www.mitov.com/free_downloads

+0

請解釋一下 - 「使用單獨連接」下的含義是什麼? –

+0

Pre v2.5客戶端庫不是線程安全的。這意味着您必須使用隔離連接進行後臺查詢。 – rstrelba

+0

但如何創建這樣的背景查詢? –