1. 程式人生 > >Win7 Qt5.4.1+VS2013編譯Oracle驅動,連線Oracle資料庫

Win7 Qt5.4.1+VS2013編譯Oracle驅動,連線Oracle資料庫

Qt開發環境描述,​Qt版本是qt-opensource-windows-x86-msvc2013-5.4.1,安裝時已選擇安裝原始碼,安裝目錄是D:\Tools\Qt5.4.1。 instantclient-sdk-nt-12.1.0.2.0.zip 和 執行環境 instantclient-basic-nt-12.1.0.2.0.zip。 instantclient-sdk-nt-12.1.0.2.0.zip解壓後,就得到Oracle客戶端的開發包,我的解壓目錄是D:\oracle\sdk
進入目錄D:\Tools\Qt5.4.1\5.4\Src\qtbase\src\plugins\sqldrivers\oci,使用VS2013開啟oci.pro,
並設定標頭檔案的包含目錄是D:\oracle\sdk\include,附加庫目錄需要包含D:\oracle\sdk\lib\msvc,連結庫的附加依賴項加入oci.lib。 注意,如果不包含oci.lib會報告一堆“無法解析外部符號 OCIXXXX”的錯誤資訊。 按下快捷鍵F7開始構建,最終報錯“無法解析的外部符號”。這是因為Qt標頭檔案包含出錯導致,具體原因不明(可能包含了Qt原始碼的標頭檔案導致混亂)。
開啟專案屬性,看到附加包含目錄的內容
修改後如下圖所示,其中5.4.1是我安裝的Qt的版本號,可根據情況自行修改,如果目錄不對會報告“無法開啟包含檔案”的錯誤。
設定好後,按下F7,就會編譯成功,我們目前編譯的是Debug版本

到目錄D:\Tools\Qt5.4.1\5.4\Src\qtbase\plugins\sqldrivers中找到剛剛生成的qsqlocid.dll,拷貝到D:\Tools\Qt5.4.1\5.4\msvc2013\plugins\sqldrivers中。如果需要釋出應用程式,那麼在應用程式所在的目錄中新建資料夾sqldrivers,把qsqlocid.dll拷貝進行就可以了。
建立Qt控制檯程式測試一下(例子摘自網上) #include <QDebug> #include <QSqlQuery> #include <QSqlError> #include <QSqlDatabase>
#include <QCoreApplication> #include <QLibrary> /**連線Oracle資料庫 *資料庫名:abc *表名:my_oracle *使用者名稱:system *密碼:123 *埠號:(預設)1521 */ void connectOracle(QString sIp, int iPort, QString sDbNm, QString sUserNm, QString sPwd) { QSqlDatabase db = QSqlDatabase::addDatabase("QOCI"); db.setHostName(sIp); db.setPort(iPort); db.setDatabaseName(sDbNm); db.setUserName(sUserNm); db.setPassword(sPwd); if (db.open()) { qDebug() << "success\n"; } else { qDebug() << "error_Oracle:\n" << db.lastError().text(); return; } //查詢語句   QSqlQuery query("select IPCID,IPCName,IPCRtspAddrMain from IPCInfo"); while (query.next()) { QString id = query.value(0).toString(); QString name = query.value(1).toString(); qDebug() << id << " --- " << name; } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QStringList lists = QSqlDatabase::drivers(); for (int i = 0; i < lists.size(); ++i) { qDebug() << lists.at(i); } connectOracle("192.168.0.1", 1521, "dbname", "user", "pwd"); return a.exec(); } 編譯執行後,連線Oracle資料庫成功,並查詢出資料。這兒我編譯的是32位的驅動,連線的是64位的Oracle 11g。
不要高興地太早,這事還沒有完。 把程式釋出後,執行,報告"QOCI driver not loaded"
還記得剛開始下載的檔案instantclient-basic-nt-12.1.0.2.0.zip嗎?這個就是oracle的執行環境,加壓到D:\oracle_run目錄中 然後在程式碼開始的位置加入以下程式碼 QLibrary *hello_lib = NULL; hello_lib = new QLibrary("D:\\oracle_run\\oci.dll"); //載入動態庫  
hello_lib->load(); if (!hello_lib->isLoaded()) { qDebug() << "load Oracle failed!\n"; return; } 再次編譯執行,終於連線上Oracle資料庫並且查詢到資料了。這只是在Win7下可以正常執行,如果把程式釋出到Xp執行,會報告一個錯誤 “無法定位程式輸入點WSAPoll於動態連結庫WS2-32.DLL上”,原因就是xp下面的ws_32.dll不包含WSAPoll這個API。那麼把win7下面的ws3_32.dll 拷貝到xp中可以嗎?當然不可以。我猜Oracle最新的執行環境使用了新技術,可能不能執行在XP中了,但它原先的執行環境肯定能執行在XP中,那就 將執行環境降級,一個一個地試一試。 找到oracle 11g最早的客戶端instantclient-basic-win32-11.1.0.6.0.zip,測試了一下,很不錯,測試程式能執行在xp、win7(32/64位)、win10中,成功連線資料庫,獲取資料。如果你嫌執行時太大,可以把不必要的檔案都刪除掉,其實也省不了多大的空間,因為最大的檔案oraociei11.dll(100M)不能去掉。 最終測試程式碼如下 #include <QDebug> #include <QSqlQuery> #include <QSqlError> #include <QSqlDatabase> #include <QCoreApplication> #include <QLibrary> /**連線Oracle資料庫 *資料庫名:abc *表名:my_oracle *使用者名稱:system *密碼:123 *埠號:(預設)1521 */ void connectOracle(QString sIp, int iPort, QString sDbNm, QString sUserNm, QString sPwd) { QLibrary *hello_lib = NULL; hello_lib = new QLibrary(qApp->applicationDirPath() + "/oracle/oci.dll"); //載入動態庫   hello_lib->load(); if (!hello_lib->isLoaded()) { qDebug() << "load Oracle failed!\n"; return; } QSqlDatabase db = QSqlDatabase::addDatabase("QOCI"); db.setHostName(sIp); db.setPort(iPort); db.setDatabaseName(sDbNm); db.setUserName(sUserNm); db.setPassword(sPwd); if (db.open()) { qDebug() << "success\n"; } else { qDebug() << "error_Oracle:\n" << db.lastError().text(); return; } //查詢語句   QSqlQuery query("select IPCID,IPCName,IPCRtspAddrMain from IPCInfo"); while (query.next()) { QString id = query.value(0).toString(); QString name = query.value(1).toString(); qDebug() << id << " --- " << name; } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QStringList lists = QSqlDatabase::drivers(); for (int i = 0; i < lists.size(); ++i) { qDebug() << lists.at(i); } connectOracle("192.168.0.7", 1521, "orcl", "icms", "icms"); return a.exec(); }