1. 程式人生 > >Qt 多執行緒與資料庫操作需要注意的幾點問題

Qt 多執行緒與資料庫操作需要注意的幾點問題

相關文章

徹底拋棄MFC, 全面應用Qt 已經不少時間了。除了自己看書按步就班做了十幾個驗證性的應用,還正式做了3個比較大的行業應用,總體感覺很好。Native C++ 下, Qt 基本是我用過的最簡便的介面庫了。遇到了一些問題,大都解決的很順利,回頭想想,還是有幾個問題很有意思,尤其是資料庫應用。這裡把我的經歷分享一下。

1、執行緒內註冊與連線資料庫的競爭問題

        文件上對多執行緒下資料庫應用的注意事項寫的很簡明,一個執行緒建立的 QSqlDatabase 物件和 查出來的 QSqlQuery 物件只能給本執行緒用(注意,是物件,不是資料庫連線本身,連線本身用名字可以多執行緒使用),其他情況是“不支援的”。在一個需要有幾個執行緒併發訪問不同資料庫的應用中,我首先試圖在各個執行緒的起始分別以不同的名稱呼叫  addDatabase / database 、open,但是程式偶然會崩潰,跟蹤後發現,雖然Qt 聲稱很多方法是“執行緒安全”的,但是幾個方法串起來,就出問題了。Qt 會動態的載入資料庫的plugin, 載入 plug in 的部分,涉及到對本地庫檔案的管理,這一部分,出現了競爭。於是,很自然的想到在初始連線部分設定 Mutex 保護,從 addDatabase / database到 open 的部分,要保證其原子性,問題再也沒有出現。

2、資料庫連線意外斷裂後,恢復連線的問題

      在MFC 中,一旦中途TCP連線斷裂,直接重新 Open 就可以了。在Qt 裡,這一招不好使了。即便 呼叫了 close ,再次open 也是不行的。處理方法:

      在檢測到問題出現後,關閉連線,並 removeDatabase;   而後,不要立刻 addDatabase, 反而是要回到該連線所在的事件迴圈。沒有詳細跟原始碼,很可能在 removeDatabase 後的事件迴圈中,Qt 內部做了一些釋放操作。   怎麼辦呢, 可以設定一個恢復定時器,比如 1分鐘,重新 addDatabase,就可以啦。如果心急的話,直接顯式呼叫processEvent() 方法強制迴圈。

      在多執行緒下,注意1中的問題,需要 Mutex保護。

3、資料庫外掛的依賴性問題

      在 Windows 下,有時我們的機器上按了好幾個 Qt 版本,PATH裡索性神馬也不設定,依賴開發環境的繼承環境適應不同的版本。這有兩個問題。一是釋出程式的時候,資料庫驅動依賴的dll 也要與可執行檔案在同一路徑下發布。比如 mysql 的 dll, PostgreSQL 的依賴等。二是在整合開發環境中,這些依賴也要位於執行檔資料夾下。否則,會造成雖然可以列舉到可用驅動,但是死活連線不上。除錯一下就知道,原來是在路徑中找不到依賴項,導致dll載入失敗哦!

     Qt的資料庫操作自成一派,相對於複雜的 ADO \ODBC\DAO\OLEDB 等傳統 C++ 訪問資料庫的方法,還是很先進的,充分體現了 OO 的理念。對資料庫的封裝,想法是很有意思的。設計者把程序內的資料庫連線作為一種資源,每個連線有一個唯一的名字,可以通過全域性的 addDatabase, removeDatabase, cloneDatabase 來增刪,想用的時候,直接用全域性的 database 來獲取。這樣的好處,是大大節省了開發者的負擔。以前為了傳遞一個數據庫連線的變數,必須在很多方法入庫處新增指向這個變數的指標或者引用,有時候不得不在物件的屬性中加入靜態的變數,來記錄這個連線。現在,什麼時候想用,給個名字就可以了,不需要傳遞。當然,文件說的是比較簡化的,至少有兩點要注意,

     1)這些增刪方法號稱是執行緒安全的,但是,在實際應用中,還是要注意用 Mutex 保護全域性建立流程,或者,過載這些函式,建立自己的安全版本。

     2)一個執行緒建立的資料庫物件(如 addDatabase 的返回值)只能在同一執行緒使用,但是,addDatabase 註冊的連線(名字是開發者定)可以跨執行緒使用,唯一需要注意的是,在呼叫全域性方法的時候,要有原子保護。