2010-02-21 65 views
7

我想在後臺線程中執行數據庫查詢。 OmniThread庫將幫助我解決所有線程問題,但有一件事我目前不明白:如何正確訪問在後臺線程中創建的查詢結果?

每個線程都需要單獨的數據庫連接。後臺線程因此創建數據庫連接,創建查詢並執行它。

現在我可以使用後臺線程的查詢對象訪問查詢結果。
但是在執行查詢後,我想要訪問主線程中的查詢結果

如果我只是引用後臺線程查詢對象,這是否會導致問題,因爲我正在訪問另一個線程中的數據庫連接?

據我所知,在這種情況下,主線程不會有它的單獨的數據庫連接,並使用後臺線程,這是不好的。

我的思維在哪裏被扭曲,以及正確的方法是什麼?

回答

12

如果您的OTL任務需要加載符合條件的企業的排序列表:

// create and open query to fetch list of companies 
while not qryCompanies.Eof do begin 
    C := TCompany.Create; 
    try 
    C.LoadFromDataset(qryCompanies); 
    Companies.Add(C); 
    except 
    C.Free; 
    raise; 
    end; 
    qryCompanies.Next; 
end; 

C是一個公司的業務對象。它可能由對象實現(TCompany)或接口(ICompany)。 CompaniesTList<TCompany>TList<ICompany>。在任務結束時,你的公司的名單發送給VCL線程:

Task.Comm.Send(TOmniMessage.Create(MSGID_LIST_OF_COMPANIES, Companies)); 

在形式要顯示你處理otlEventMonitor實例的OnTaskMessage事件正在監視你的任務企業名單:

procedure TListBaseFrame.otlEventMonitorTaskMessage(
    const task: IOmniTaskControl); 
var 
    MsgID: word; 
    MsgValue: TOmniValue; 
begin 
    task.Comm.Receive(MsgID, MsgValue); 
    Assert(MsgValue.IsInterface); 
    if fLoaderTask = task then begin 
    SetLoadedData(MsgID, MsgValue.AsInterface); // or MsgValue.AsObject); 
    fLoaderTask := nil; 
    end; 
end; 

公司列表替換以前的列表,並可以顯示在網格中。

同樣,您可以返回一個公司對象/界面進行顯示和編輯。

兩件事情是值得我們思考:

  • 如果你至今最好的對象接口,編寫多線程程序可能是一個理由重新考慮。如果您在後臺線程中創建對象,然後將它們傳遞給VCL線程並在後臺線程中忘記它們,則對象可能會正常工作。然而,我發現通過在應用程序中緩存對象以及僅從數據庫加載尚未加載或已更改的記錄,可以獲得更好的性能。我所有的表都有變化指數(64位整數,時間戳可能工作以及)連接到它,那就是改變了每次更新。相反,執行

    select * from foo where (...) order by (...) 
    

    的我只執行一個

    select id, change_index from foo where (...) order by (...) 
    

    然後在高速緩存中檢查是否有相同的ID(主鍵)和變化指數已經存在,如果這樣返回緩存的對象對象,並且只有在不創建新業務對象並加載所有列的情況下。

    但如果緩存中的對象,你將不得不從多個線程,和所有權問題對它們的引用很快得到那麼複雜,基於引用計數的生命週期管理是保持清醒的唯一途徑。在這方面使用接口而不是對象有很多幫助。

  • 添加同步對象到每個業務對象是必要的,如果多個線程可以同時訪問它們。這當然是可能的,但可能會引入額外的複雜性和潛在的僵局。如果您將業務對象實現爲不可變的,那麼根本不需要鎖。我越來越多地使用這種方法,雖然它需要一些適應它,但它可以簡化很多事情。

+0

完美!這正是我錯過的......將結果轉移到其他線程的方式。 非常感謝! – Holgerwa 2010-02-21 13:12:46

+0

+1很好的答案! – jpfollenius 2010-02-21 15:23:02

+0

像往常一樣好的答案! – gabr 2010-02-21 15:45:52

5

最好的方法可能是在GUI中不使用db-aware組件。線程應該與數據庫進行通信並將信息存儲在業務對象中,然後可以將其發送到主線程(將顯示它們)。

多線程很難,不僅從實現的角度而且從應用程序設計的角度來看。通常情況下,如果您將後臺線程視爲具有明確定義的輸入和輸出的單獨層,那麼最好。

+0

「..和存儲業務對象的信息。」 這就是我堅持這一點。我不使用任何數據感知組件,我只需要將查詢結果數據傳送到主線程。 你把什麼稱爲業務對象? – Holgerwa 2010-02-21 10:57:16

+1

業務對象=包含從您的數據庫中的數據類的實例,轉化爲面向對象的編程方式(即看起來並不像一個SQL結果,但就像你在紙上設計的東西,當你研究你的問題)。 – gabr 2010-02-21 13:08:11

相關問題