Qt 多線程與數據庫操作需要注意的幾點問題


源地址:http://blog.csdn.net/goldenhawking/article/details/10811409

 徹底拋棄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 注冊的連接(名字是開發者定)可以跨線程使用,唯一需要注意的是,在調用全局方法的時候,要有原子保護。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM