资讯动态

Delphi老项目连接Oracle:ODAC选型与实战避坑指南

发布时间:2026/10/18 11:10:13 来源:尧图企业网站定制
简介ODACOracle Data Access Components是Devart为Delphi与CBuilder开发者打造的Oracle数据库访问组件库本资源即围绕其核心连接控件展开适合需要在中高级数据库应用中快速接入Oracle的开发者。包内共1807个文件以pas源码、dcu编译单元、dfm窗体、dpk与bpl包文件为主辅以res资源、bmp图标、xfm/nfm跨平台窗体及dpr、cpp工程文件压缩包约9.7MB覆盖组件源码、示例工程与编译产物。资源重点呈现TOracleConnection连接管理、TOracleQuery查询、TOracleTable数据表、TOracleTransaction事务以及存储过程与函数调用等模块并涉及连接池、异步操作、数据绑定与错误日志等实用特性支持从Oracle 8i到19c的多个版本。已有467人学习下载可帮助读者理解ODAC组件结构、复用示例工程并掌握Oracle连接与数据操作的排错思路。1. 为什么老 Delphi 项目还在用 ODAC 连 Oracle一次真实选型复盘接手一个跑了七八年的 Delphi 老系统时数据库连接层往往是最不想动又最躲不开的部分。这套系统用的是 Oracle客户端环境五花八门有的机器装了完整客户端有的只扔了一个 Instant Client 目录进去。之前用 ADO 那套换台机器就报 ORA-12154排查半天发现是 tnsnames.ora 路径不对。后来换成 ODACOracle Data Access Components情况好了很多——它不依赖系统 ODBC 数据源直连模式只需要一个 oci.dll 就能跑起来。ODAC 是 Devart 出的 Delphi/CBuilder 数据库连接组件库专门针对 Oracle 做了深度封装。它跟 Delphi 自带的 dbExpress 或者 ADO 最大的区别在于直连模式Direct Mode不需要装 Oracle 客户端组件自己解析协议跟数据库通信。这对部署环境不可控的老项目来说省了太多事。适合谁用维护 Delphi 遗留系统、需要连 Oracle 但不想折腾客户端安装、或者要在同一套代码里同时支持多种连接方式的场景。2. ODAC 核心组件拆解TOraSession 与 TOraQuery 怎么配2.1 连接层TOraSession 的关键参数TOraSession 是整个 ODAC 的核心所有查询、事务、元数据操作都挂在它下面。配置连接有两种模式Client Mode 和 Direct Mode。Client Mode 走的是 Oracle 官方 OCI 接口需要机器上有 oci.dll完整客户端或 Instant Client 都行。Direct Mode 不走 OCI组件内部自己实现了 Oracle 的网络协议理论上不需要任何 Oracle 客户端文件。但 Direct Mode 有个硬限制不支持某些高级特性比如 Oracle Wallet 的部分功能、某些加密算法。我一般这样配// Client Mode 配置示例 OraSession1.Server : 192.168.1.100:1521/orcl; OraSession1.Username : app_user; OraSession1.Password : app_pass; OraSession1.ConnectMode : cmNormal; OraSession1.Options.Direct : False; // 走 OCI OraSession1.LoginPrompt : False; OraSession1.Connect; // Direct Mode 配置示例 OraSession1.Server : 192.168.1.100:1521/orcl; OraSession1.Username : app_user; OraSession1.Password : app_pass; OraSession1.Options.Direct : True; // 直连不需要 oci.dll OraSession1.Connect;Server 参数的格式是主机:端口/服务名注意这里是服务名不是 SID。如果数据库用的是 SID得写成主机:端口:SID。这个细节坑过不少人——连接串写错了报 ORA-12514 或者 ORA-12505查半天以为是网络问题。Options.Direct 设成 True 之后ODAC 会走自己的协议栈。实测在 Oracle 11g 和 12c 上都能正常工作19c 也没问题。但如果你用了 Oracle 的 Advanced Security 选项比如网络加密、数据完整性校验Direct Mode 可能不支持得切回 Client Mode。2.2 查询层TOraQuery 与 TOraSQL 的分工TOraQuery 继承自 TCustomDADataSet用法跟 TADOQuery 很像但针对 Oracle 做了优化。TOraSQL 则是专门用来执行不返回结果集的语句比如 INSERT、UPDATE、DDL。// TOraQuery 查询示例 OraQuery1.Session : OraSession1; OraQuery1.SQL.Text : SELECT emp_id, emp_name, hire_date FROM employees WHERE dept_id :deptId; OraQuery1.ParamByName(deptId).AsInteger : 10; OraQuery1.Open; while not OraQuery1.Eof do begin // 处理数据 Memo1.Lines.Add(OraQuery1.FieldByName(emp_name).AsString); OraQuery1.Next; end; OraQuery1.Close; // TOraSQL 执行示例 OraSQL1.Session : OraSession1; OraSQL1.SQL.Text : UPDATE employees SET salary salary * 1.1 WHERE dept_id :deptId; OraSQL1.ParamByName(deptId).AsInteger : 10; OraSQL1.Execute;TOraQuery 的 FetchAll 属性值得注意。默认是 False意味着它是按需从服务器拉数据适合大结果集。如果设成 True打开时一次性把所有数据拉到本地小结果集查询会快一些但内存占用会上去。我一般保持默认除非明确知道结果集很小。参数绑定用:paramName的命名参数比 ADO 的?占位符可读性好很多。ParamByName 取值时要注意类型匹配——AsInteger、AsString、AsDateTime 这些方法会做类型转换但如果数据库字段是 NUMBER 而参数传了字符串可能报类型转换错误。2.3 事务与连接池ODAC 的事务控制挂在 TOraSession 上OraSession1.StartTransaction; try OraSQL1.Execute; OraSQL2.Execute; OraSession1.Commit; except OraSession1.Rollback; raise; end;连接池方面ODAC 内置了 Pooling 机制。在 TOraSession 的 Options 里可以设 Pooling True然后配 MaxPoolSize 和 MinPoolSize。但要注意连接池是按 TOraSession 实例隔离的如果你在程序里到处 Create 新的 TOraSession池子就形同虚设。常见做法是全局维护一个 TOraSession或者用连接池管理器统一分配。3. 从零跑通第一个 ODAC 连接环境准备与代码落地3.1 环境准备清单在动手之前确认这几样东西到位项目要求备注Delphi 版本Delphi 7 到 11 Alexandria 都支持不同版本对应不同 ODAC 安装包ODAC 版本跟 Delphi 版本匹配装错版本 IDE 里看不到组件Oracle 客户端Client Mode 需要 oci.dllDirect Mode 可跳过目标 Oracle9i 到 21c 都支持具体看 ODAC 版本说明网络能通到 Oracle 监听端口默认 1521ODAC 安装时会往 IDE 里注册组件包。装完之后在 Tool Palette 的 Devart 分类下能看到 TOraSession、TOraQuery、TOraSQL、TOraStoredProc 这些。如果看不到检查 Library Path 里有没有 ODAC 的 Source 和 Lib 目录。3.2 最小可运行示例新建一个 VCL Forms Application拖一个 TOraSession、一个 TOraQuery、一个 TDataSource、一个 TDBGrid 上去。procedure TForm1.FormCreate(Sender: TObject); begin // 配置连接 OraSession1.Server : 127.0.0.1:1521/XEPDB1; OraSession1.Username : system; OraSession1.Password : oracle; OraSession1.Options.Direct : True; // 先用直连模式试 OraSession1.LoginPrompt : False; try OraSession1.Connect; ShowMessage(连接成功); except on E: Exception do begin ShowMessage(连接失败: E.Message); Exit; end; end; // 配置查询 OraQuery1.Session : OraSession1; OraQuery1.SQL.Text : SELECT table_name, num_rows FROM user_tables ORDER BY table_name; OraQuery1.Open; // 绑定到界面 DataSource1.DataSet : OraQuery1; DBGrid1.DataSource : DataSource1; end;这段代码的逻辑很直白先配 Session 的连接参数调 Connect 建立连接然后把 Query 挂到 Session 上设 SQL 语句Open 执行查询最后通过 DataSource 把结果集绑到 DBGrid 显示。几个参数说明一下。Server 里的XEPDB1是 Oracle 18c XE 的默认可插拔数据库服务名如果你用的是传统实例换成对应的服务名。Options.Direct 设 True 时ODAC 不走 OCI直接跟 Oracle 的 TNS 监听通信。LoginPrompt 设 False 避免弹出登录框适合自动化部署。3.3 连接失败时的排查路径连接报错时按这个顺序查第一步确认网络通不通。telnet 主机 1521或者用tnsping测。如果端口不通先解决网络问题。第二步确认服务名对不对。SELECT value FROM v$parameter WHERE nameservice_names在数据库服务器上查一下。连接串里的服务名必须跟这个一致。第三步确认账号密码。用 SQL*Plus 或者 SQL Developer 先试一下排除账号本身的问题。第四步看 ODAC 的报错信息。ODAC 的异常信息比 ADO 详细很多通常会带上 Oracle 的错误码。ORA-12154 是 TNS 解析失败ORA-12514 是服务名不对ORA-28000 是账号被锁。提示Direct Mode 下如果报 Net: Invalid argument 之类的错误先检查 Server 字符串格式。必须是主机:端口/服务名冒号和斜杠都不能少。4. 避坑指南ODAC 连接 Oracle 的五个血泪教训4.1 坑一Direct Mode 下中文乱码现象用 Direct Mode 连上之后查询出来的中文字段全是问号或者乱码。原因Direct Mode 不走 OCI字符集转换由 ODAC 自己处理。如果客户端字符集跟数据库字符集不匹配就会乱码。解决在 TOraSession 的 Options 里显式设置 Charset。比如数据库是 AL32UTF8客户端设成 UTF8OraSession1.Options.Charset : UTF8; OraSession1.Options.UseUnicode : True;如果还是乱码检查 Delphi 的字符串类型。Delphi 2009 之后默认是 UnicodeString跟 ODAC 的 Unicode 支持配合没问题。Delphi 7 的话得用 WideString 或者手动转码。4.2 坑二连接池泄漏导致 ORA-00020现象程序跑一段时间后报 ORA-00020提示超过了最大会话数。原因每次操作都 Create 一个新的 TOraSession用完没 Free连接池里的连接越积越多。解决全局维护一个 TOraSession 实例或者用 try...finally 确保每次用完都释放var Session: TOraSession; begin Session : TOraSession.Create(nil); try Session.Server : ...; Session.Connect; // 执行操作 finally Session.Free; // 确保释放 end; end;如果确实需要多个连接用 ODAC 的连接池管理设好 MaxPoolSize别让它无限增长。4.3 坑三TOraQuery 的 FetchAll 设错导致内存暴涨现象查询一个大表程序内存直接飙到几个 G最后 OutOfMemory。原因FetchAll 设成了 TrueODAC 一次性把所有数据拉到本地内存。解决保持 FetchAll False默认值让 ODAC 按需拉取。如果确实需要一次性加载先评估结果集大小或者用分页查询。4.4 坑四Client Mode 下找不到 oci.dll现象程序在开发机上跑得好好的部署到客户机器上报 Cannot load OCI DLL。原因客户机器上没装 Oracle 客户端或者 oci.dll 不在 PATH 里。解决要么改用 Direct Mode要么把 Instant Client 的目录加到 PATH或者在代码里显式指定 OCI 路径OraSession1.Options.OCIDLL : C:\instantclient_19_8\oci.dll;注意 Instant Client 的版本要跟目标 Oracle 版本兼容。19c 的 Instant Client 连 11g 一般没问题反过来可能不行。4.5 坑五事务没提交导致锁表现象程序执行了 UPDATE 但没 Commit其他会话查同一张表时卡住。原因ODAC 默认是手动提交模式执行完 DML 后必须显式 Commit。解决要么在代码里显式 Commit要么把 TOraSession 的 Options.AutoCommit 设成 True。但 AutoCommit 有性能影响每条语句都提交一次大批量操作时会慢很多。我一般还是手动控制事务边界。5. 进阶技巧用 TOraStoredProc 调存储过程与性能调优5.1 存储过程调用的正确姿势TOraStoredProc 是 ODAC 里专门调存储过程的组件。跟 TOraQuery 不同它需要显式定义参数方向。// 假设有个存储过程 proc_get_employee(p_id IN NUMBER, p_name OUT VARCHAR2) OraStoredProc1.Session : OraSession1; OraStoredProc1.StoredProcName : proc_get_employee; OraStoredProc1.Prepare; OraStoredProc1.ParamByName(p_id).AsInteger : 1001; OraStoredProc1.ExecProc; ShowMessage(员工姓名: OraStoredProc1.ParamByName(p_name).AsString);关键点是 Prepare 方法。它会把存储过程的参数元数据从数据库拉下来自动创建对应的参数对象。如果不调 Prepare 直接设 ParamByName会报参数不存在的错误。对于返回游标的存储过程用 TOraStoredProc 的 Open 方法而不是 ExecProcOraStoredProc1.StoredProcName : proc_get_employees; OraStoredProc1.Prepare; OraStoredProc1.ParamByName(p_dept_id).AsInteger : 10; OraStoredProc1.Open; // 返回游标时用 Open5.2 性能调优的几个开关ODAC 有几个影响性能的选项值得根据场景调整选项默认值建议说明Options.DirectFalse部署环境不可控时设 True省去客户端安装Options.UseUnicodeFalse有中文时设 True避免乱码FetchAllFalse保持 False大结果集必须Options.AutoCommitFalse保持 False手动控制事务Options.QueryTimeout0按需设0 表示不超时另外TOraQuery 的 SQL 语句尽量用参数绑定别拼字符串。参数绑定不仅防 SQL 注入还能让 Oracle 复用执行计划减少硬解析。5.3 一个验证连接是否健康的习惯从那以后我每次部署完 ODAC 程序都强制走一遍这个检查先用 Direct Mode 连一次再用 Client Mode 连一次各跑一条SELECT 1 FROM DUAL。Direct Mode 验证组件本身没问题Client Mode 验证 OCI 环境没问题。两个都通了才敢交给测试。这个习惯帮我提前发现过好几次问题——有一次客户机器上装了 32 位的 Oracle 客户端而程序是 64 位的Client Mode 直接加载不了 oci.dll但 Direct Mode 能跑。如果只测一种模式上线后肯定翻车。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑