简介QT5.13连接Oracle 11g的驱动与依赖资源包针对使用MSVC编译器、32位环境的QT开发人员解决QT连接Oracle时驱动不匹配、OCI依赖缺失等常见问题。压缩包共51个文件包含29个头文件用于声明API、10个dll和7个lib提供编译链接与运行时支持、4个sym符号文件辅助调试整体大小60.63MB。已有363人学习下载。包内已编译好qsqloci.dll与qsqlocid.dll驱动整合了oci.dll、oraociei11.dll、oraocci11.dll等Oracle客户端库以及全部所需头文件并附说明文档可直接将驱动部署至QT的sqldrivers目录使用省去手动编译驱动的环节。特别适合在32位、MSVC工具链下快速搭建QT5.13与Oracle 11g的连接环境需注意该版本驱动基于MSVC编译不能用于MinGW工程。1. 32位Qt5.13为什么连不上Oracle 11驱动去哪了QT5.13连接Oracle11的驱动和依赖32位这个压缩包说白了就是解决一件事让32位的Qt5.13程序能顺利连上Oracle 11g数据库。很多人第一次接触它都是在同一个报错里翻车的程序里写了QSqlDatabase加了QOCI驱动名结果运行起来直接弹一行“QSqlDatabase: QOCI driver not loaded”。这时候如果去Qt安装目录翻plugins/sqldrivers会发现只有qsqlite、qmysql这些根本没有qsqloci.dll这个东西。原因不复杂Qt官方预编译包从很早开始就不再附带Oracle驱动只把驱动源码放到src里让开发者自己编。要连Oracle必须有一个qsqloci.dll插件还得有一整套OCI客户端运行库陪它一起工作。本标题里的这个rar就是把“驱动插件 依赖DLL”按32位打包好的一个现成方案省去自己去翻Oracle官网、配环境变量、折腾编译器的过程。这篇笔记适合谁正在维护老系统、用32位Qt写桌面工具要对接Oracle 11g数据库、或者刚收到这么个rar不知道往哪放的开发者。下面按“包里有什么 → 怎么装 → 踩了哪些坑 → 没有包怎么自己编”的顺序讲清楚。2. 驱动与依赖清单qsqloci.dll和OCI客户端是怎么配合的2.1 Qt的SQL驱动是插件qsqloci.dll的加载机制Qt对数据库的支持走的是插件机制。程序启动时QSqlDatabase会到插件目录里扫描所有以qsql开头的DLL发现哪个就注册哪个。这个插件目录通常有两种来源一是Qt安装目录下的plugins/sqldrivers二是应用程序可执行文件旁边的sqldrivers目录。如果你用静态编译或用了windeployqt工具部署过后者会出现否则就走前者。qsqloci.dll这个插件本身不直接实现Oracle网络协议它做的是把QSqlDatabase的调用翻译成OCIOracle Call Interface函数调用。OCI是Oracle提供的一套C语言接口真正的SQL解析、网络通信、结果集返回全部由它完成。所以qsqloci.dll只负责“翻译”而OCI客户端DLL负责“干活”。少了任何一个连接都起不来。这就是为什么官方Qt安装包不带Oracle驱动的原因之一光给qsqloci.dll没用用户机器上还得有一整套OCI运行库而OCI运行库属于Oracle客户端的知识产权和发行范围Qt没有义务也不能轻易把它塞进安装包。所以源头上的做法是驱动你自己编或找人编OCI客户端你自己从Oracle官网下载。而这个32位rar就是把这些东西集中打包的产物。2.2 32位依赖清单核对压缩包里缺什么一个能正常工作的32位Oracle连接方案解压后大致需要这几类文件分类典型文件名作用Qt驱动插件qsqloci.dllQSqlDatabase加载的Oracle驱动OCI核心库oci.dllOCI入口qsqloci.dll直接链接它OCI数据字典oraociei11.dll字符集、错误消息、语言数据OCI轻量库oraociicus11.dll轻量版OCI用于Instant Client安全加密相关orannzsbb11.dll、oraopw11.dll加密和口令相关C运行库msvcp140.dll、vcruntime140.dll如果Qt是MSVC编译的MinGW运行库libgcc_s_dw2-1.dll、libstdc-6.dll、libwinpthread-1.dll如果Qt是MinGW编译的网络配置tnsnames.ora、sqlnet.ora让连接串能解析成数据库地址拿到rar后我建议先对照这个表核对一遍。最常见的问题是包里只有qsqloci.dll没有OCI那串DLL。这种包装了必报driver not loaded。反过来如果OCI DLL齐了但运行库缺了会报“找不到msvcp140.dll”之类的系统弹窗属于Windows加载DLL阶段就失败了。2.3 位数和编译器ABI32位驱动不能配64位OCI这里面有个容易踩翻车的匹配链Qt程序进程位数 → qsqloci.dll位数 → OCI DLL位数 → Oracle客户端位数四者必须全部一致差一位都不行。一个32位的Qt进程只能加载32位的DLL如果你往里面塞64位的oci.dllWindows加载器要么弹“不是有效的Win32应用程序”要么干脆让QOCI在驱动列表里消失。编译器类型同样卡得死。MinGW版Qt的动态库链接的是msvcrt或MinGW运行库MSVC版Qt链接的是msvcp140。这两类qsqloci.dll不能互换否则就算文件名字一样加载时也可能因为导出符号不一致而静默失败Qt的提示还是那一句“driver not loaded”不会告诉你具体是哪个DLL出了问题。这也是为什么下载现成rar时必须确认它匹配自己的“Qt位数 编译器类型”而不能只看文件名里写着Oracle 11和32位就无脑用。3. 让驱动跑起来安装路径与最小连接验证3.1 安装步骤插件目录和OCI库的摆放位置解压rar之后关键动作只有两个把qsqloci.dll放到Qt能扫到的sqldrivers目录把OCI那一堆DLL放到进程能找得到的地方。后者有三种常见做法放到exe同目录、放到PATH环境变量包含的目录、在程序里调用AddDllDirectory提前指定。对桌面应用来说最简单稳定的是exe同目录。如果只是在开发机上让调试程序跑通操作如下rem 把插件放入Qt的sqldrivers目录以MinGW 32位版为例 copy qsqloci.dll C:\Qt\Qt5.13.0\5.13\mingw73_32\plugins\sqldrivers\ rem 把OCI依赖放入运行目录 copy oci.dll oraociei11.dll oraociicus11.dll orannzsbb11.dll C:\myapp\debug\ rem 验证依赖能否被找到 set PATHC:\myapp\debug;%PATH%如果连的是远程数据库服务器还需要把tnsnames.ora放到某个目录并设置TNS_ADMIN指向它。这一步经常被忽略后面第4章的避坑会专门讲。逻辑不复杂qsqloci.dll负责让驱动被识别OCI DLL负责让驱动能完成真实连接两个动作缺一不可。参数上需要注意如果客户端数据库字符集比较老道比如库是GBK而程序要显示中文在解压包里通常会带一个使用说明或批处理来设置NLS_LANG这个环境变量务必按库的实际字符集设不能图省事不设。3.2 用C代码验证QOCI是否加载成功放好文件后先用一段最简代码验证驱动加载和连接不要上来就接业务逻辑。这样即使失败问题范围也小。参考代码#include QCoreApplication #include QSqlDatabase #include QSqlError #include QDebug int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); // 打印当前Qt能识别的所有数据库驱动 qDebug() available drivers: QSqlDatabase::drivers(); // 手动加载QOCI QSqlDatabase db QSqlDatabase::addDatabase(QOCI, test_conn); db.setHostName(192.168.1.10); // Oracle服务器地址 db.setPort(1521); // Oracle默认监听端口 db.setDatabaseName(ORCL); // TNS名或 service_name db.setUserName(scott); // 数据库用户 db.setPassword(tiger); // 密码测试用生产建议走加密配置 if (!db.open()) { qDebug() open failed: db.lastError().text(); return 1; } qDebug() open oracle success; return 0; }这段代码先通过QSqlDatabase::drivers()看看qsqloci.dll有没有被成功识别。如果列表里没有“QOCI”说明插件没被加载后面所有操作都是白搭如果有但open失败再看lastError区分是网络、账号还是TNS问题。这种分层排查方式能省很多时间。连接参数里最容易被写错的是setDatabaseName。它可以填tnsnames.ora里的网络服务名也可以直接填“host:port/service_name”形式的EZ Connect串。只有在你确定不依赖tnsnames.ora时后者才更直接。端口1521是Oracle默认端口如果服务器改过监听端口这里必须同步调整否则报ORA-12541。3.3 连接串与TNS_ADMIN驱动能加载不等于能建连驱动加载成功只是第一步。很多人卡在这QOCI出现在驱动列表里但open()永远返回失败错误是ORA-12154。这个错误几乎都是TNS解析失败导致的。Oracle客户端拿到“ORCL”这个字符串后会去tnsnames.ora里查它的真实地址查不到就报错。tnsnames.ora里一条基本配置长这样ORCL (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST 192.168.1.10)(PORT 1521)) (CONNECT_DATA (SERVICE_NAME orcl)) )注意Oracle 11g里较多使用SERVICE_NAME而不是旧的SID如果你的库是11g RAC或单实例但注册名是服务名SID写法很可能解析不到。常见的排查动作是先在本机用sqlplus用同一份tnsnames.ora测通再回来调Qt程序。这样能把问题明确切割成“客户端配置问题”和“驱动加载问题”。TNS_ADMIN环境变量决定了客户端去哪个目录找tnsnames.ora。开发机和部署机的目录结构经常不一样开发机跑得好好的程序拷到别的机器就报ORA-12154十有八九是环境变量没有跟随程序一起走。后面第6章会给出一个部署脚本把TNS_ADMIN固化到程序目录里避免这类环境依赖。4. QOCI驱动加载失败的5条高频避坑记录4.1 driver not loaded文件却都在现象把解压出来的文件都放到了对应位置QSqlDatabase::drivers()里还是没有QOCI程序报“QSqlDatabase: QOCI driver not loaded”。原因文件在不代表文件能被加载。最常见的是OCI DLL依赖了一个缺失的运行库Windows加载器加载qsqloci.dll时发现它的依赖链断裂于是整体跳过。第二个常见原因是位数不匹配把64位OCI放进了32位程序目录。解决用Dependencies或dumpbin查看qsqloci.dll的导入表确认依赖的oci.dll等库都在搜索路径里再用任务管理器或Process Explorer确认进程是32位而不是Qt程序装错了位数。我见过最典型的血泪案例是表面看文件齐了实际上程序目录里同时存在一个旧版的oci.dll版本太老还导出了同名符号结果覆盖了正确版本加载是加载了但调用就崩。用进程加载模块列表去核对实际加载的DLL路径能避开这类隐形覆盖。4.2 ORA-12154TNS无法解析连接串现象驱动列表里QOCI正常出现程序也能编译能运行但open()失败错误码ORA-12154。原因Qt把setDatabaseName的值原样传给OCI客户端客户端按TNS名去解析结果没找到。可能原因有三tnsnames.ora不在TNS_ADMIN指向的目录里文件里没有对应的网络服务名条目连接串里混入了换行或不可见字符导致匹配不上。解决先检查环境变量TNS_ADMIN是否为有效目录再做一个小测试在OCI客户端目录下用sqlplus执行“conn scott/tigerORCL”验证同样的连接串能否成功。若能成功问题一定在Qt程序与环境的衔接上若同样失败那就是tnsnames.ora写错了。特别注意某些rar包会自带一份tnsnames.ora示例直接复制时容易把示例里的host写成固定IP要改成实际服务器地址。4.3 中文乱码NLS_LANG没设或设错现象连接正常数据能查出来但中文全部显示成问号或乱码部分情况还会报ORA-12705。原因Oracle客户端与数据库字符集不一致。Oracle服务器端的字符集是ZHS16GBK或AL32UTF8时客户端NLS_LANG必须匹配或能正确转换。Qt侧拿到的字符串默认按UTF-8处理如果OCI返回的是GBK字节流而程序按UTF-8解码就会乱。解决设置环境变量NLS_LANG为与库一致的值常见是“AMERICAN_AMERICA.AL32UTF8”或“SIMPLIFIED CHINESE_CHINA.ZHS16GBK”。如果库是AL32UTF8客户端也用AL32UTF8Qt侧无需额外转码如果库是GBK而客户端用AL32UTF8需要关注Qt的QTextCodec层转码。部署阶段建议把NLS_LANG写进启动脚本因为它不会随rar自动生效需要手动加到系统环境变量或程序启动参数里。4.4 ORA-12541监听和主机端口问题现象open()失败错误码ORA-12541提示TNS:no listener。原因这个错和驱动本身无关纯粹是网络层没找到监听进程。常见于服务器防火墙没放行1521端口服务器监听的端口被改过主机名解析到了错误IP。解决先在本机用tnsping命令测试给出的TNS名或host:port是否能通。tnsping成功说明监听可达问题在账号权限或数据库状态tnsping失败则检查主机可达性、端口占用和防火墙。我之前遇到过一台机器Oracle正常但监听器服务被手动停掉忘了拉起来tnsping报no listener重启监听器服务就行了。这类问题不要纠结在Qt代码上它只是个客户端调用方。4.5 MinGW驱动放进了MSVC版Qt现象拿到手上的rar里qsqloci.dll看起来没问题放好之后程序启动直接崩溃或加载时报0xc000007b。原因0xc000007b这个错误码几乎就是DLL位数或ABI不匹配的经典标志。MinGW和MSVC编译的DLL虽然都是32位但运行时库和C ABI约定不同如果把MinGW编出的qsqloci.dll放进MSVC版Qt的sqldrivers目录插件即使被识别为QOCI内部调用也很可能因为符号约定不一致崩溃。解决下载或编译驱动前先确认自己的Qt是从哪个编译器来的。Windows下Qt5.13常见的是mingw73_32和msvc2017_32这两条路径名字里已经写了编译器类型。去Qt安装目录看一眼就知道然后选对应的包。如果压缩包内附带的说明标注了编译环境优先按说明匹配没标注的启动就崩的基本可以直接放弃不用浪费时间去调试。5. 没有现成驱动包时用OCI SDK自己编译qsqloci.dll5.1 准备Instant Client和Qt源码目录不是每次都能恰好找到匹配的rar。项目里接手过一个32位MinGW工程网上找的驱动包全部是MSVC编译放进去就崩最后只能自己编。手动编译并没有想象中复杂前提是原料齐全。需要两样东西Oracle官方Instant Client for Windows x8632位以及Qt5.13对应版本的头文件和源码中的sqldrivers目录。如果安装Qt时勾选了Sources组件源码在Qt安装目录下的Src/qtbase/src/plugins/sqldrivers/oracle里如果没勾重跑安装程序补上Sources组件即可。Instant Client解压后关键路径有两个sdk/include目录里面有oci.h等头文件以及sdk/lib/msvc目录里面有oci.lib导入库。MinGW环境一般不能用MSVC的导入库但可以借助reimp工具把oci.lib转成MinGW能用的liboci.a更省事的方式是在pro文件里直接用-L和-l链接让这一步在编译时处理。5.2 修改qsqloracle.pro并编译进到oracle插件源码目录后需要给qmake传两个关键路径。打开qsqloracle.pro核心内容如下# 进入Qt源码的Oracle插件目录 cd C:\Qt\Qt5.13.0\Src\qtbase\src\plugins\sqldrivers\oracle # 配置OCI头文件和库目录然后执行qmake qmake INCLUDEPATHC:/instantclient_11_2/sdk/include \ LIBS-LC:/instantclient_11_2/sdk/lib/msvc -loci # MinGW环境用这个命令编译 mingw32-make release # MSVC环境用这个命令编译 nmake release编译完成后在release子目录里会生成qsqloci.dll这个就是目标产物。注意编译使用的Qt版本和编译器决定了这个qsqloci.dll能被哪个Qt程序加载。用5.13的MinGW编出来的别的Qt版本不一定兼容所以编之前先确认目标环境。LIBS参数是编译链接阶段的导入库路径。这里的一个坑是如果lib目录下只有oci.libMSVC格式MinGW的gcc链接器不一定能直接处理常见做法是用gendef和dlltool从oci.dll自己生成一个MinGW导入库或者把链接方式改成运行时LoadLibrary动态加载。这两种做法都需要额外几步但对32位MinGW环境来说比强行混用MSVC导入库更稳妥。5.3 编译产物的发布不要把整个Oracle拿出去自己编译的qsqloci.dll生成之后发布到目标机器时同样需要搭配OCI客户端。这里容易犯的错误是把整个Instant Client目录几十甚至几百MB都拷过去或者干脆装一个完整Oracle客户端。实际上只要把oci.dll、oraociei11.dll、oraociicus11.dll等运行库DLL拷到exe同目录即可不需要安装程序也不影响其他软件。发布时建议精简到最小集合先试连接再按报错逐步补DLL。但这种“缺什么补什么”的方式要小心补的时候只能补到程序目录或OCI专用目录不要往系统System32里塞否则会和机器上已有的Oracle客户端产生DLL冲突把开发机蔓延出来的“玄学问题”带到客户现场。6. 把驱动、依赖和连接配置写成一条命令部署6.1 一键部署脚本驱动、OCI、TNS参数一起就位经验多了之后我习惯把整套东西整理成一个bat脚本每次部署新机器就是双击执行一条命令把踩过的坑固化进去。脚本内容大致是这样echo off set APP_DIRC:\myapp set OCI_DIR%APP_DIR%\oci set TNS_DIR%APP_DIR%\network rem 1. 确保sqldrivers目录存在并把qsqloci.dll放进去 mkdir %APP_DIR%\sqldrivers 2nul copy qsqloci.dll %APP_DIR%\sqldrivers\ /Y rem 2. 把OCI依赖放好 mkdir %OCI_DIR% 2nul copy oci.dll oraociei11.dll oraociicus11.dll orannzsbb11.dll %OCI_DIR%\ /Y rem 3. 把tnsnames.ora放到固定目录并设置TNS_ADMIN mkdir %TNS_DIR% 2nul copy tnsnames.ora %TNS_DIR%\ /Y setx TNS_ADMIN %TNS_DIR% rem 4. 设置字符集环境变量避免中文乱码 setx NLS_LANG AMERICAN_AMERICA.AL32UTF8 rem 5. 启动程序 %APP_DIR%\myapp.exesetx写入的是用户级环境变量对当前会话不生效所以脚本最后直接启动程序时用的还是老的TNS_ADMIN。更稳的处理是启动前在bat内用“set TNS_ADMIN...”临时设置让本次启动立即生效再用setx为后续启动持久化。这行顺序看起来不起眼实际部署时吃过不少亏脚本写好了双击启动程序还是报ORA-12154原因就是当前cmd会话没有重读环境变量。6.2 部署后必做的驱动加载检查每次换新机器我不会直接打开业务系统验证而是先跑第3章那段最小连接代码。这一步能快速区分是环境问题还是业务代码问题省得业务系统启动时报一堆无关错误干扰判断。检查时关注三点目录下实际加载的是不是sqldrivers里的qsqloci.dll任务管理器里进程位数是不是32位tnsping能否通。三步都过了再跑业务系统。如果某一步失败直接回到第4章的对应条目处理基本不超过五分钟就能定位。有一次部署到客户机器所有DLL都齐了tnsping也通但程序就是报driver not loaded折腾半天发现机器系统目录里残留了一个旧版qsqloci.dll应用加载路径优先级把它给拦走了。从那以后我每次部署都用Process Explorer确认实际加载路径不再只看“文件存在”。希望这个习惯能帮到你。本文还有配套的精品资源点击获取