QT5.13+VS2019连接Oracle11

文章目录

  • 环境
  • 一、编译QOCI驱动
    • 1.1 下载QT源码和MSVC
    • 1.2 获取Oracle11的SDK
    • 1.3 QT源码编译 QOCI 驱动
  • 二、QT连接Oracle
    • 2.1 编写代码
    • 2.2 添加运行时的动态库
    • 2.3 部署到发布机(要求能连接上服务端)
  • 三、连接时提示NLS错误的解决方案
  • 四、连接时提示无法识别SID的解决方案
  • 四、已编译的驱动打包
  • 参考资料

环境

  • 开发环境:Windows10 1803 + VS2019 + QT5.13
  • 数据库服务端环境:Win7 x64 + Oracle11g x86 服务端
  • 客户端部署环境:Win7 x32 + Oracle11g x86 客户端

一、编译QOCI驱动

1.1 下载QT源码和MSVC

  • QT不再内置oracle驱动,需要自己用qt源码编译驱动(QOCI)
  • 因为我的部署环境要求32位的支持,所以安装QT时选择:MSVC2017 x86 、Source
    QT5.13+VS2019连接Oracle11_第1张图片

1.2 获取Oracle11的SDK

  • 用QT源码编译驱动时需要Oracle11的头文件、动态库、lib库,稳妥的办法是从已安装Oracle11的电脑上拷贝这些文件,或者在开发环境上安装一个Oracle11(客户端或服务端都行)
    Oracle11.2客户端32位官网下载:https://www.oracle.com/database/technologies/112010-win32soft.html
    Oracle11.2客户端64位官网下载:https://www.oracle.com/database/technologies/112010-win64soft.html
    QT5.13+VS2019连接Oracle11_第2张图片
  • 安装后,QT编译需要的头文件(oic.h等)和lib库都在oci文件夹内,动态库(oci.dll、oraocci11.dll)在bin文件夹内,由于我的开发环境是win10不能安装oracle11,所以我把这些文件都单独拷贝出来了。
    QT5.13+VS2019连接Oracle11_第3张图片
    QT5.13+VS2019连接Oracle11_第4张图片

1.3 QT源码编译 QOCI 驱动

  • 打开源码
    打开目录C:\Qt\Qt5.13.1\5.13.1\Src\qtbase\src\plugins\sqldrivers\oci下的oci.pro项目文件

  • 第一次打开项目时需要配置项目的构建套件,但MSVC的套件不能直接选择,需要手动添加一个:
    点击option - 克隆一个MSVC 32bit - 选择Compiler为MSVC x86 - 确定 - 选择克隆的MSVC 32bit - Configure Project
    QT5.13+VS2019连接Oracle11_第5张图片
    QT5.13+VS2019连接Oracle11_第6张图片
    QT5.13+VS2019连接Oracle11_第7张图片

  • 尝试直接编译,提示:Library 'oci' is not defined
    QT5.13+VS2019连接Oracle11_第8张图片
    解决办法:修改项目文件oci.pro为以下内容(如果是MSVC就添加oci.lib路径,如果是minGW就添加oci.dll路径)
    QT5.13+VS2019连接Oracle11_第9张图片

    TARGET = qsqloci
    
    HEADERS += $$PWD/qsql_oci_p.h
    SOURCES += $$PWD/qsql_oci.cpp $$PWD/main.cpp
    
    #注释该行
    #QMAKE_USE += oci
    
    #根据Oracle客户端安装路径 指定oci.dll(minGW) 或 oci.lib(MSVC)
    QMAKE_LFLAGS +=C:\myOCI\lib\msvc\oci.lib
    
    #根据Oracle客户端安装路径 指定头文件和lib库路径
    INCLUDEPATH += C:\myOCI\include
    LIBPATH += C:\myOCI\lib\msvc
    
    darwin:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ
    
    OTHER_FILES += oci.json
    
  • 右键项目-重新构建,提示:error: C3861: “OCIBindByPos2”: 找不到标识符
    QT5.13+VS2019连接Oracle11_第10张图片
    解决方案:双击错误提示转到报错的cpp文件,修改代码:
    QT5.13+VS2019连接Oracle11_第11张图片

    // binding the column
    //r = OCIBindByPos2(
    r = OCIBindByPos(
        d->sql, &bindColumn.bindh, d->err, i + 1,
        bindColumn.data,
        bindColumn.maxLen,
        bindColumn.bindAs,
        bindColumn.indicators,
        //bindColumn.lengths,
        reinterpret_cast<ub2*>(bindColumn.lengths),
        0,
        arrayBind ? bindColumn.maxarr_len : 0,
        arrayBind ? &bindColumn.curelep : 0,
        OCI_DEFAULT);
    
  • 右键项目-重新构建,驱动编译成功,在C:\plugins\sqldrivers目录下可以看到生成的DLL文件
    QT5.13+VS2019连接Oracle11_第12张图片

  • 将DLL拷贝至QT的C:\Qt\Qt5.13.1\5.13.1\msvc2017\plugins\sqldrivers就可以正常使用了(如果是用MinGW编译的驱动就拷贝至MinGW下)
    QT5.13+VS2019连接Oracle11_第13张图片

二、QT连接Oracle

2.1 编写代码

  • 在VS编写的QT项目中添加SQL模块
    QT5.13+VS2019连接Oracle11_第14张图片
  • 代码:
    #include
    #include
    #include
    #include
    LED::LED(QWidget* parent)
    	: QMainWindow(parent)
    {
    	ui.setupUi(this);
    
    	QSqlDatabase db = QSqlDatabase::addDatabase("QOCI");
    	db.setHostName("172.16.6.20");  //数据库服务端IP
    	db.setPort(1521);				//端口
    	db.setDatabaseName("bsoft");	//数据库服务名
    	db.setUserName("portal_his");	//账号
    	db.setPassword("123456");		//密码
    	if (db.open())
    	{
    		MessageBox(0, 0, L"成功连接Oracle", 0);
    	}
    	else
    	{
    		QString str= db.lastError().text();
    		MessageBoxA(0, str.toLocal8Bit(), 0, 0);
    		qDebug() << db.lastError();
    	}
    }
    

2.2 添加运行时的动态库

  • 如果直接调试运行exe,会提示driver not loaded
    解决方案:将QT编译的QOCI驱动文件、oracle11的Bin目录下的oci.dll都拷贝到exe同目录
  • 再次调试运行exe,提示unable to logon
    解决方案:将oraociei11.dll(从instantclient 或 oracle11服务端拷贝)也放到exe同目录。(CSDN下载:https://download.csdn.net/download/forchoosen/12683536)
    QT5.13+VS2019连接Oracle11_第15张图片

2.3 部署到发布机(要求能连接上服务端)

  • 发布机上不要求安装任何Oracle客户端,只要求能ping通oracle服务端
  • 由于是QT项目,所以需要用添加QT动态库(参考https://blog.csdn.net/forchoosen/article/details/104091156)
    QT5.13+VS2019连接Oracle11_第16张图片
  • 运行
    QT5.13+VS2019连接Oracle11_第17张图片

三、连接时提示NLS错误的解决方案

  • 问题描述
    在发布机上直接运行exe可以连接,但是如果安装了oracle9i客户端,运行时提示ORA-12705: Cannot access NLS data files or invalid environment specified
    QT5.13+VS2019连接Oracle11_第18张图片
    这是由于oracle9i安装程序将注册表键NLS_LANG的值设为NA

  • 解决方案:
    NLS_LANG的值设为SIMPLIFIED CHINESE_CHINA.ZHS16GBK就可以了(注意oracle9i在注册表中的3个位置有NLS_LANG,都要改):
    QT5.13+VS2019连接Oracle11_第19张图片

    需要注意的是,不同系统中的NLS_LANG的位置不相同,所以稳妥的办法是在注册表编辑器中搜索这个键:
    QT5.13+VS2019连接Oracle11_第20张图片
    写成批处理(以Win7 x64下的oracle9i为例):

    	REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\" /V NLS_LANG /T REG_SZ /D "SIMPLIFIED CHINESE_CHINA.ZHS16GBK" /F
    	REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\ALL_HOMES\ID0\" /V NLS_LANG /T REG_SZ /D "SIMPLIFIED CHINESE_CHINA.ZHS16GBK" /F
    	REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\HOME0\" /V NLS_LANG /T REG_SZ /D "SIMPLIFIED CHINESE_CHINA.ZHS16GBK" /F
    	pause
    

    写成 *.reg 文件(Win7 x86/x64 oracle9i):

    Windows Registry Editor Version 5.00
    
    ;--------------------------------------------------- 32λ Windows7 ---------------------------
    [HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE]
    "NLS_LANG"="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\ALL_HOMES\ID0]
    "NLS_LANG"="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME0]
    "NLS_LANG"="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    
    ;--------------------------------------------------- 64λ Windows7 ---------------------------
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE]
    "NLS_LANG"="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\ALL_HOMES\ID0]
    "NLS_LANG"="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\HOME0]
    "NLS_LANG"="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
    

四、连接时提示无法识别SID的解决方案

  • 问题描述
    ORA-ORA-12505: TNS: 监听程序当前无法识别连接描述符中所给出的 SID

  • 原因分析
    与PL/SQL客户端不同,QT连接oracle时在QSqlDatabase.setDatabaseName(XXX)中设置的是数据库实例名(SID),而不是服务名或数据库名(SERVICE_NAME),所以不能用tnsnames.ora文件中的SERVICE_NAME:
    QT5.13+VS2019连接Oracle11_第21张图片

  • 解决方案
    执行SQL以查询实例名:select * from v$instance
    QT5.13+VS2019连接Oracle11_第22张图片
    填入QSqlDatabase.setDatabaseName("bsoft")

四、已编译的驱动打包

  • CSDN下载:https://download.csdn.net/download/forchoosen/12683551

参考资料

  • 【Qt】Qt5.12版本编译Oracle驱动教程
  • Win10 Qt5.12 oracle11g 64位下编译oci驱动 Qt5.12远程连接Oracle数据库
  • https://dl.pconline.com.cn/download/1359403-1.html?=1331694031
  • Oracle客户端工具出现“Cannot access NLS data files or invalid environment specified”错误的解决办法
  • oracle数据库名、实例名、ORACLE_SID

你可能感兴趣的:(QT-学习笔记)