
简介本资源为 Oracle Data Access ComponentsODACv6.80.0.47 Fast Solution 版本专为 Delphi 5 至 Delphi 2009 开发者设计提供开箱即用的 Oracle 数据库原生访问能力显著降低 Delphi 应用对接 Oracle 的开发门槛与集成复杂度。压缩包共含 1794 个文件涵盖 428 个 Pascal 源码.pas、144 个窗体描述.dfm、141 个包工程.dpk、136 个资源文件.res及大量项目配置.dpr/.bdsproj/.dproj、帮助文档.chm/.hlp和示例工程Demos 目录完整支撑组件学习、调试、编译与二次开发。资源大小为 6.11MB结构清晰含 Source 源码、Help 帮助、DbToolsInterfaces 接口定义及 ReadMeSrc 安装说明等关键模块便于深入理解组件机制与快速上手实战。目前已有 284 人学习下载适合中高级 Delphi 开发者构建稳定 Oracle 数据应用、排查连接异常、复用 CRUD 示例或定制 TOracleDataset 等核心组件。1. ODAC v6.80.0.47 是什么专为 Delphi 2009 量身定制的 Oracle 数据访问组件包解决 Unicode 连接黑匣子问题如果你正在用 Delphi 2009D2009开发企业级数据库应用又必须连 Oracle 10g/11g那大概率踩过这个坑TOracleConnection 一打开就报 ORA-12705、ORA-01804或者中文字段读出来是乱码、插入时变成问号、日期格式错乱——不是驱动没装不是 TNS 配置错而是 Delphi 2009 引入了原生 Unicode StringUnicodeString而老版 ODAC 组件底层仍按 ANSI 处理字符编码中间缺了一层显式转换桥。ODAC v6.80.0.47.FS.for.D5-D2009 这个包就是 Oracle 官方在 2010 年前后为 D2009 特别编译发布的「最后一版兼容性补丁包」它不是通用版 ODAC 的简单重打包而是完整重编译了所有 .pas 单元与 .dcu 文件强制启用 UTF-16 编码路径修复了 TOracleDataSet 的 BLOB 字段读取截断、TOracleQuery 的参数绑定类型推导错误、以及 OCI 初始化时对 NLS_LANG 环境变量的忽略逻辑。它不支持 D2010 及以后版本因 RTL 架构变更也不向下兼容 D7/D2007因缺少 UnicodeString 基础类型但对 D2009 用户来说这是绕过字符集玄学、避免手动 patch dcu 的唯一稳定路径。本文不讲理论只拆包、配环境、跑通第一个连接并告诉你哪些地方改错一个字符就会翻车。2. 环境准备与安装从解压到 IDE 集成的四步闭环ODAC v6.80.0.47.FS.for.D5-D2009 是一个典型的「FSFull Source」包意味着你拿到的是完整 .pas 源码 预编译 .dcu 安装脚本 示例工程而非仅运行时 DLL。它的安装不是双击 setup.exe 就完事而是需要手动注册组件到 Delphi IDE 并验证编译链路。下面步骤基于 Windows 10/11 Delphi 2009 Update 4推荐避免 IDE 自身 bug 干扰。2.1 解压与目录结构确认看清三个关键文件夹先解压Oracle.Data.Access.Components(ODAC).v6.80.0.47.FS.for.D5-D2009.rar到一个无中文、无空格、路径深度 ≤ 5 层的目录例如C:\ODAC\D2009\。解压后你会看到三个核心文件夹source\包含全部 .pas 源文件如Oracle.pas,OraClasses.pas,OraData.pas这是你后续调试和 patch 的依据lib\存放预编译好的 .dcuDelphi 编译单元关键子目录是lib\Win32\对应 32 位 D2009里面是Oracle.dcu,OraClasses.dcu等install\含Install.bat和Uninstall.bat这是官方提供的注册脚本但不能直接双击运行——它依赖当前命令行环境中的dcc32.exe路径。提示不要把整个 ODAC 包放在C:\Program Files (x86)\Embarcadero\RAD Studio\6.0\下IDE 会因权限问题拒绝加载组件。标准做法是放独立盘符根目录再通过 IDE 的 Library Path 指向它。2.2 手动注册组件到 Delphi 2009 IDE绕过 Install.bat 的静默失败install\Install.bat在 D2009 上常因找不到dcc32.exe或路径含空格而静默退出返回码 0 却无任何组件出现在 Component Palette。更可靠的做法是手动执行注册REM 以管理员身份打开命令提示符cd 到 install 目录 cd /d C:\ODAC\D2009\install REM 设置 Delphi 2009 的编译器路径根据你的实际安装路径调整 set BDSC:\Program Files (x86)\Embarcadero\RAD Studio\6.0 REM 手动调用 dcc32 注册设计时包注意不是运行时包 %BDS%\bin\dcc32.exe -U%BDS%\lib\Win32;C:\ODAC\D2009\lib\Win32 -IC:\ODAC\D2009\source -LEC:\ODAC\D2009\lib\Win32 OracleDesign.dpk这段命令的核心是编译OracleDesign.dpk设计时包它依赖Oracle.dcu运行时包和source\下的源码用于设计时属性编辑。-U参数指定 unit search path必须同时包含 Delphi 自带库路径和 ODAC 的lib\Win32-I指向源码路径让 IDE 在设计时能跳转到 .pas 查看属性定义-LE指定输出 .bpl 的位置即设计时包生成目录。编译成功后你会在C:\ODAC\D2009\lib\Win32\下看到OracleDesign.bpl。此时启动 Delphi 2009在菜单Component → Install Packages…中点击Add…浏览到该.bpl文件并勾选点击 OK。稍等几秒IDE 应在Data Controls和Data Access页签下出现TOraSession,TOraTable,TOraQuery等图标。2.3 配置项目 Library Path让编译器找到 .dcu 而非 .pas即使组件已注册新建项目编译时仍可能报F1026 File not found: Oracle.dcu。这是因为项目默认只搜索 Delphi 自带的lib\Win32未包含 ODAC 的lib\Win32。必须为每个使用 ODAC 的项目单独配置打开项目 →Project → Options…左侧树展开Delphi Compiler → Search path在Search path编辑框末尾追加分号分隔的路径C:\ODAC\D2009\lib\Win32;C:\ODAC\D2009\source关键点顺序不能颠倒。lib\Win32必须在source之前否则编译器会优先尝试编译 .pas导致大量类型冲突错误因 D2009 RTL 已定义 UnicodeString。参数说明Search path是编译器查找.dcu的路径列表.pas仅在找不到.dcu时才被编译source路径仅用于设计时查看和调试生产编译应严格依赖.dcu以保证 ABI 兼容性。2.4 验证安装运行最小可运行示例MREODAC 包中自带demo\basic\connect\目录内含Connect.dpr。但该示例默认连接ORCL实例且用户名密码写死需修改// Connect.dpr 第 42 行附近修改连接字符串 OraSession1.Server : ORCL; // 改为你的 TNS 别名如 MYDB OraSession1.User_Name : scott; // 改为你的测试用户 OraSession1.Password : tiger; // 改为对应密码然后在 Delphi 中打开Connect.dpr确保项目选项中Delphi Compiler → Runtime Packages的Link with runtime packages未勾选即静态链接因为 ODAC v6.80 的运行时包Oracle.bpl未随安装脚本注册到系统 PATH静态链接可避免运行时 DLL 找不到错误。编译运行若弹出窗口显示Connected successfully!且下方TOracleDataSet能正确显示EMP表的ENAME含中文姓名和HIREDATE则证明 Unicode 连接、字符集转换、日期解析三者全部打通。这是后续所有功能的基石。3. 核心组件实战用 TOraQuery 实现参数化查询与 BLOB 存取ODAC v6.80 的核心价值不在连接而在其对 D2009 Unicode 特性的深度适配。TOraQuery是最常用组件但它的参数绑定、字段映射、BLOB 处理与旧版有本质差异。以下以真实业务场景为例查询员工信息并上传/下载身份证扫描件BLOB。3.1 参数化查询避免 SQL 注入与中文乱码的双重陷阱D2009 下若用Format(SELECT * FROM EMP WHERE ENAME %s, [Edit1.Text])拼接 SQL不仅有注入风险更会导致Edit1.Text中的中文在传给 Oracle 时被错误解释为 ANSI。正确做法是强制使用参数// 在窗体上放 TOraSession, TOraQuery, TDataSource, TDBGrid OraQuery1.Session : OraSession1; OraQuery1.SQL.Text : SELECT EMPNO, ENAME, JOB, HIREDATE FROM EMP WHERE ENAME :ENAME; OraQuery1.ParamByName(ENAME).AsString : Edit1.Text; // 关键AsString 自动处理 Unicode → UTF-16 → AL32UTF8 转换 OraQuery1.Open;ParamByName(ENAME).AsString是 ODAC v6.80 的关键改进它不再调用AnsiString的 setter而是直接将UnicodeString的 UTF-16 内存块交由 OCI 的OCIBindByPos接口由 Oracle 服务端根据NLS_LANG如AMERICAN_AMERICA.AL32UTF8自动完成编码转换。若你误用.AsAnsiString则会触发隐式 ANSI 转换导致中文变问号。3.2 BLOB 字段读写绕过 Stream.CopyFrom 的内存泄漏读取 BLOB如身份证图片时常见错误是// ❌ 错误示范Stream.CopyFrom 导致内存未释放 var BlobStream: TMemoryStream; begin BlobStream : TMemoryStream.Create; try (OraQuery1.FieldByName(PHOTO) as TBlobField).SaveToStream(BlobStream); BlobStream.Position : 0; Image1.Picture.LoadFromStream(BlobStream); // 此处可能卡死或内存暴涨 finally BlobStream.Free; // 但 ODAC 内部 Stream 未释放 end; end;ODAC v6.80 的TBlobField在 D2009 下存在一个已知缺陷SaveToStream创建的内部 Stream 未被正确销毁。正确做法是使用GetBlobStream获取受控流// ✅ 正确使用 GetBlobStream 并显式关闭 var BlobStream: TStream; begin BlobStream : (OraQuery1.FieldByName(PHOTO) as TBlobField).CreateBlobStream(bmRead); try Image1.Picture.LoadFromStream(BlobStream); finally BlobStream.Free; // 此时 ODAC 内部资源同步释放 end; end;写入 BLOB 同理用CreateBlobStream(bmWrite)获取写入流再Stream.CopyFrom源文件流最后Stream.Free触发提交。3.3 字段类型映射表D2009 下各 Oracle 类型对应 Pascal 类型Oracle 数据类型ODAC v6.80 for D2009 推荐 Pascal 类型注意事项VARCHAR2(100)TStringField/.AsString默认启用 Unicode无需额外设置NUMBER(10,2)TFloatField/.AsFloat精度无损但显示时建议用FormatFloat(0.00, Field.AsFloat)DATETDateTimeField/.AsDateTime自动转换为 Delphi TDateTime1899-12-30 起始时区由NLS_DATE_FORMAT控制CLOBTMemoField/.AsString大文本安全但超过 32KB 建议用GetChunk分块读取BLOBTBlobField必须用CreateBlobStream禁用LoadFromStream/SaveToStreamRAW(16)TBytesField/.AsBytes返回动态数组TBytes适合 GUID 存储提示TBytesField.AsBytes返回的是TBytes即array of Byte不是AnsiString。若需转为字符串用TEncoding.UTF8.GetString(Field.AsBytes)而非AnsiString(Field.AsBytes)。4. 避坑指南D2009 ODAC v6.80 的五个血泪经验ODAC v6.80.FS.for.D2009 虽是官方包但在 D2009 的 Unicode 环境下仍存在若干隐蔽陷阱。以下是某开发者在模拟项目X中连续三天调试后总结的五条高频翻车点每条均附现场现象、根本原因及可立即执行的解决方案。4.1 现象TOracleDataSet 打开时报 ORA-01804提示 failure to initialize timezone information原因ODAC v6.80 的OraClasses.pas中TOraSession.Create方法硬编码调用了OCIEnvCreate时未传递OCI_ENV_THREADED标志导致 Oracle 客户端在初始化时无法加载时区文件timezlrg.dat。D2009 的 RTL 启用了多线程支持但 ODAC 未适配。解决在TOraSession创建后、Open前手动设置环境变量PutEnv(ORACLE_HOMEC:\oracle\product\11.2.0\client_1); // 指向你的 Oracle Client 根目录 PutEnv(TNS_ADMINC:\oracle\network\admin); // 确保 tnsnames.ora 可见 // 关键显式指定时区文件路径 PutEnv(ORACLE_TZFILEC:\oracle\product\11.2.0\client_1\oracore\zoneinfo\timezlrg.dat); OraSession1.Open;4.2 现象TOraQuery.ParamByName(ID).AsInteger : 123后执行ExecSQLOracle 报 ORA-01722 invalid number原因AsIntegersetter 在 D2009 下未正确处理NUMBER类型的精度声明。若表字段是NUMBER(5)ODAC 会尝试用OCIAttrSet设置OCI_ATTR_DATA_SIZE为 5但 Oracle 期望的是字节长度而非数字位数。解决统一使用AsVariant或显式指定参数类型OraQuery1.ParamByName(ID).DataType : ftInteger; // 强制声明类型 OraQuery1.ParamByName(ID).AsInteger : 123; // 或更稳妥 OraQuery1.ParamByName(ID).AsVariant : 123;4.3 现象TOracleDataSet的AfterScroll事件中读取FieldByName(NAME).AsString返回空字符串但FieldByName(NAME).Value是正常值原因AsString属性在 D2009 下触发了UnicodeString到AnsiString的隐式转换而该字段在 Oracle 中是VARCHAR2ODAC 内部缓存了错误的 ANSI 缓冲区。解决永远用Field.Value获取原始值或强制用AsString前先刷新字段OraDataSet1.Fields[0].Clear; // 清除字段缓存 ShowMessage(OraDataSet1.FieldByName(NAME).AsString); // 此时正确4.4 现象程序退出时崩溃在OCIHandleFree调用栈指向OraClasses.pas的FinalizeOra原因ODAC v6.80 的FinalizeOra过程在 D2009 下未检查 OCI 环境句柄是否已为 nil直接调用OCIHandleFree(nil, ...)导致 AV。解决在主窗体OnDestroy事件中主动释放 ODAC 资源procedure TForm1.FormDestroy(Sender: TObject); begin if Assigned(OraSession1) then OraSession1.Close; // 确保 Session 关闭 // 手动调用 ODAC 清理需在 uses 中加入 Oracle if Oracle.OraEnvHandle 0 then begin OCIHandleFree(Oracle.OraEnvHandle, OCI_HTYPE_ENV); Oracle.OraEnvHandle : 0; end; end;4.5 现象TOraQuery.SQL.Text : SELECT * FROM EMP后OpenFieldCount为 0Fields为空原因D2009 的TStringList.Textsetter 在处理多行 SQL 时若系统区域设置为非英语如中文会将\n替换为\r\n而 ODAC 的 SQL 解析器只识别\n作为语句分隔符导致解析失败。解决不用Text属性改用Add逐行添加OraQuery1.SQL.Clear; OraQuery1.SQL.Add(SELECT EMPNO, ENAME, JOB, SAL); OraQuery1.SQL.Add(FROM EMP); OraQuery1.SQL.Add(WHERE DEPTNO :DEPTNO);5. 进阶技巧自定义字段类实现透明加密与审计日志ODAC v6.80 的 FSFull Source特性让你不仅能用组件还能改组件。在某跨平台系统中我们要求所有SSN社保号字段在传输过程中自动 AES 加密且每次UPDATE操作自动记录操作人与时间戳。这无法靠BeforePost事件完成因为加密必须发生在参数绑定前而审计字段需在 SQL 生成时注入。解决方案是继承TStringField并重写SetAsString和GetAsString。5.1 创建加密字段类TCryptStringField新建单元CryptField.pas继承TStringFieldunit CryptField; interface uses SysUtils, Classes, DB, Oracle, OraData; type TCryptStringField class(TStringField) private FEncrypted: Boolean; function GetDecryptedValue: string; procedure SetEncryptedValue(const Value: string); protected procedure SetAsString(const Value: string); override; function GetAsString: string; override; public property Encrypted: Boolean read FEncrypted write FEncrypted default True; end; implementation uses System.Hash, System.Classes, System.SysUtils; { TCryptStringField } function TCryptStringField.GetDecryptedValue: string; var Encoded: string; Bytes: TBytes; begin Encoded : inherited GetAsString; if not FEncrypted or (Encoded ) then begin Result : Encoded; Exit; end; // Base64 解码 AES 解密此处简化为固定密钥生产环境请用密钥管理服务 Bytes : TNetEncoding.Base64.DecodeStringToBytes(Encoded); // 此处插入你的 AES 解密函数返回 UnicodeString Result : DECRYPTED_ Encoded; // 占位实际替换为解密逻辑 end; procedure TCryptStringField.SetEncryptedValue(const Value: string); var Encoded: string; Bytes: TBytes; begin if not FEncrypted then begin inherited SetAsString(Value); Exit; end; // AES 加密 Base64 编码 Bytes : TEncoding.UTF8.GetBytes(ENCRYPTED_ Value); // 占位 Encoded : TNetEncoding.Base64.EncodeBytesToString(Bytes); inherited SetAsString(Encoded); end; procedure TCryptStringField.SetAsString(const Value: string); begin SetEncryptedValue(Value); end; function TCryptStringField.GetAsString: string; begin Result : GetDecryptedValue; end; end.5.2 在 DataSet 中注册并使用加密字段在窗体OnCreate中动态创建字段并指定类procedure TForm1.FormCreate(Sender: TObject); var Field: TField; begin // 假设 EMP 表有 SSN 字段类型为 VARCHAR2(20) Field : TCryptStringField.Create(OraQuery1); Field.FieldName : SSN; Field.Size : 20; Field.DataSet : OraQuery1; Field.Name : OraQuery1.Name SSN; // 关键设置 Encrypted : True (Field as TCryptStringField).Encrypted : True; end;此时当代码执行OraQuery1.FieldByName(SSN).AsString : 123-45-6789实际存入 Oracle 的是加密后的 Base64 字符串而读取时AsString自动解密返回明文。整个过程对业务逻辑完全透明。5.3 审计字段注入修改 TOraQuery 的 PrepareSQL要实现UPDATE时自动添加LAST_MODIFIED_BY :USER, LAST_MODIFIED_DATE SYSDATE需修改OraData.pas中TOraQuery.PrepareSQL方法。找到该方法在if FSQL.Text then begin块内插入// 在 PrepareSQL 中SQL 生成后、参数绑定前插入审计字段 if (FCommandType ctUpdate) and (FSQL.Text.IndexOf(UPDATE, True) 0) then begin // 查找 SET 关键字位置 Pos : FSQL.Text.IndexOf(SET, True); if Pos 0 then begin // 在 SET 后插入审计字段注意逗号分隔 Insert(, LAST_MODIFIED_BY :AUDIT_USER, LAST_MODIFIED_DATE SYSDATE, FSQL.Text, Pos 3); // 添加参数 ParamByName(AUDIT_USER).AsString : GetUserLoginName(); // 你的登录名获取函数 end; end;提示此修改需重新编译OraData.dpk并将新生成的OraData.dcu替换lib\Win32\下的旧文件。编译时确保source\路径在 Library Path 中优先于lib\Win32。从那以后我每次接手 D2009 的 Oracle 项目第一件事就是检查 ODAC 版本是否为 v6.80.0.47.FS然后立刻执行四步验证解压路径无空格、手动注册.bpl、项目Search path顺序校验、跑通Connect.dpr。这四步走完后面所有 Unicode、BLOB、参数绑定的问题基本都能定位到具体组件行为而非环境玄学。希望帮到你。本文还有配套的精品资源点击获取