尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ZeosDBO 6.0.12源码编译与安装:老项目数据库访问层迁移的稳定选择

ZeosDBO 6.0.12源码编译与安装:老项目数据库访问层迁移的稳定选择 简介zeosdbo-6.0.12 最新稳定版源码是一套面向 Delphi、C Builder、Kylix 等 Borland 编译器的原生数据库组件库。其核心效用在于通过统一的本地数据集与数据库组件将 MySQL、PostgreSQL、InterBase、Firebird、MS SQL、Sybase 等多种数据库的差异封装起来并额外提供正则表达式和 SQL 解析对象使开发者能更高效地完成跨数据库应用开发与数据访问层迁移。资源包内共收录 387 个文件以 pas 源文件为主体覆盖组件实现的核心逻辑配合 dpk、bpg 等工程与包管理文件以及 res、cfg、dof 等资源和配置可还原完整编译环境同时附有 dll、inc、changes、knownbugs、license 等辅助材料便于对照文档进行源码阅读与二次开发。整个压缩包仅 1.19MB轻量易得当前已有 267 人学习使用。对希望深入理解数据库组件封装机制、需要定制或扩展现有数据访问层的中高级开发者而言这套源码提供了可直接编译调试的完整工程可一边跟踪 SQL 解析流程一边实践组件扩展方法。从实际项目角度看完整源码对定位连接异常、驱动冲突等问题也有直接帮助。1. 从源码包到可用组件为什么老项目仍需要 ZeosDBO 6.0.12一个从 Delphi XE 时代活下来的老项目数据库是 PostgreSQL界面是 VCL业务逻辑全部写在 TDataSet 的字段事件里。从迁移到 Lazarus 的第一天开始我就意识到真正难啃的不是界面而是数据访问层。换 FireDAC 意味着重写一大片 SQL换 ADS 又是另一套数据库抽象。最终救场的就是 zeosdbo 6.0.12 最新稳定版源码包一份用纯 Pascal 写的数据库访问组件一个 TZConnection 就能把 MySQL、PostgreSQL、SQLite、Firebird 的差异挡在业务代码之外。这个源码包不是给刚入门的新手看的而是给那些被商业组件锁定、又不想被 IDE 版本绑架的团队准备的。自己编译一遍组件才真正属于你。2. 版本与架构一份源码包该有的前置认知在动手执行任何编译指令之前得先把“为什么是它”这件事想清楚。很多人一看到源码就直接打开三个小时后卡在某个单元编译错误上才开始往回翻文档。2.1 为什么锁定 6.0.12 而不是追 7.x稳定版的取舍逻辑ZeosDBO 的版本线很有意思。6.0.x 是一个长期维护分支它的任务是修补驱动错误、跟进数据库版本而不是推翻既有 API。而 7.x 一直处在开发状态组件命名、连接模型、异步支持都有大改动但迟迟没有进入正式发行。对一个要交付给客户的项目来说“最新稳定版源码”的意思不是追新功能而是拿一个足够长时间没人改 API 的版本作为基线。zeosdbo 6.0.12 就是这条基线。6.0.12 的源码里驱动层分为 ZDbc 抽象层和各数据库的 DBC 驱动。你可以把 DBC 驱动理解成数据库的方言翻译器同一套连接字符串由它负责把 Zeos 内部的 ZSQL 语句编译成对应的数据库原生命令。升级 6.0 小版本号通常意味着特定的数据库驱动修复比如哪个版本的 PostgreSQL 新引入的特性在驱动层怎么映射。追丁版本如 6.0.12 之后的 6.1拖到具体项目里收益没有你想得大反而要重新做一遍全量回归。有一个真实的取舍案例团队里一份老报告用了 TZReadOnlyQuery因为 6.0 的只读数据集在内存占用上比 TZQuery 小很多。升到 7.x只读组件被合并到统一的数据集模型里迁移成本是存在的。所以对绝大多数现有工程6.0.12 是“代码改动最小、驱动修复最全”的平衡点。2.2 源码包里的三层结构从连接到数据集的调用链打开 zeosdbo 源码包建议先从 src 目录下手而不是 doc。常见做法是把源码看作三层核心层ZCore、ZParas、ZPlain负责字符集转换、连接参数解析和底层客户端 API 封装。DBC 层ZDbc 下的驱动例如 mysql、postgresql、sqlite、firebird、mssql。这一层决定了能够接哪些数据库。组件层TZConnection、TZQuery、TZUpdateSQL它们负责跟 IDE 的组件面板对接也负责把 DataSource 事件翻译回 DBC 调用。在 6.0.12 中TZConnection 并不直接持有 socket 句柄而是通过 ZPlain 层加载数据库的客户端库。例如连接 MySQL最终会调用 libmysql.dll 或者 libmariadb.dll。源码包里不会附带这些 DLL所以动手编译前必须先把对应数据库的客户端库放在系统库路径里否则会出现“运行期找不到库”的坑。这也解释了为什么源码包会被反复编译和分发每个项目的运行时环境不一样只有自己编译的这份才能踩对本机 DLL。理解了这三层结构后续的编译顺序也就自然清楚了先编核心层再编 DBC 驱动最后把组件注册到 IDE。不能跳到组件层直接编译底层 API 的接口声明还没生成。3. 编译安装把 zeosdbo 源码变成 IDE 里的组件页签从源码包到能看到组件面板是整个流程中最琐碎、也最需要耐心的一步。下面区分 Lazarus 和 Delphi 两条路径来写。3.1 Lazarus 用户按包序编译组件注册有固定顺序先把源码包解压到不带空格的路径例如D:\libs\zeosdbo-6.0.12。空格会引发 Makefile 和 FPC 编译器路径解析的历史遗留问题。打开 Lazarus 后通过 Package 菜单的 Open Package 依次加载以下包cd /d D:\libs\zeosdbo-6.0.12 # 先打开核心包编译它直到右下角状态变成 OK lazarus packages/lazarus/zcore.lpk # 编译完成后继续打开解析层 lazarus packages/lazarus/zparsing.lpk 编译顺序不可乱zcore、zparsing、zplain、zdbc、zcomponent。zcore负责基础类库和内存管理zparsing处理 SQL 解析zplain提供动态库加载zdbc是所有数据库驱动zcomponent才是真正会显示在 IDE 组件面板里的那批组件。打开每个 lpk 后在 Package 窗口点击 Compile。前四个包出现 Compile 成功即可不要急着 Install。只有最后一个包zcomponent.lpk需要点击 Install然后确认重启 IDE。重启之后组件面板会出现一个新的页签名为 Zeos Access。里面应该有 TZConnection、TZQuery、TZReadOnlyQuery、TZUpdateSQL 等组件。验证编译是否成功最简单的方式是拖一个 TZConnection 到窗体上然后查看 Object Inspector 的 Database 属性和 Protocol 属性。如果属性下拉列表里能看到mysql-5、postgresql-9.1、sqlite-3这些值说明组件注册成功。不要只看页签是否出现有的 IDE 会把组件加载到不显眼的分组里。3.2 Delphi / VCL 用户用批处理脚本批量编译6.0.12 的源码包为 VCL 用户准备了一套批处理脚本放在packages\delphi目录下。作者团队用脚本统一处理不同 RAD Studio 版本的编译器差异所以在执行之前先看目录下有哪些compile_*.bat文件选对应自己 IDE 版本的脚本执行cd packages\delphi # 以下示例是选一个与你 IDE 版本匹配的批处理文件 compile_dx.bat脚本做的事很简单调用dcc32.exe或 64 位环境下的dcc64.exe逐个编译包单元最终生成运行时包和设计时包。执行完脚本后检查窗口里有没有类似Zeos Access installed的提示。若没有打开 IDE 的 Component 菜单点击 Install Packages手动把生成的 bpl 文件添加进去。注意脚本默认输出路径可能指向源码包内部的lib目录看仔细点避免之后找不到生成物。这一步有一个容易翻车的细节脚本编译所需的 OpenSSL DLL。Zeos 在连接 HTTPS 和部分数据库协议时会用到 OpenSSL编译包里只有接口声明DLL 要自己准备。如果本机没有 OpenSSL编译过程可能报错或警告。对本地开发机先装一个不带敏感配置的 OpenSSL 运行库即可之后部署时再按目标环境处理。4. 连接与参数把 TZConnection 调通的最小配置组件注册好了接下来要让连接真正工作。这一章的参数配置会直接影响你能不能跑通第一个 SQL也会决定上线后第一天会不会被运维叫醒。4.1 一组可直接改用的连接参数以 MySQL 和 SQLite 为例TZConnection 的设计思路与 ADO 有点像用一个统一接口把数据库差异压到协议属性里。下面这段代码可以直接放进一个按钮事件里测试var Conn: TZConnection; begin Conn : TZConnection.Create(nil); try Conn.Protocol : mysql-5; Conn.HostName : 127.0.0.1; Conn.Port : 3306; Conn.User : app_user; Conn.Password : app_pass; Conn.Database : zeos_demo; Conn.ClientCodepage : UTF8; Conn.Connect; if Conn.Connected then ShowMessage(连接成功数据库版本: Conn.DBCConnection.GetServerVersion); finally Conn.Free; end; end;几个参数的含义按优先级说明。Protocol决定 Zeos 加载哪套 DBC 驱动写成mysql-5Zeos 就会去 ZPlainMySql 里找 libmysql 并模拟 MySQL 5.x 的行为。HostName与Database不用多说但有一个坑在 6.0.12 的老版本里属性名曾经是Host而不是HostName。如果你手里的源码是别人配置过的确认 Object Inspector 里显示的是哪个名字。ClientCodepage必须设置在Connect之前这个属性决定连接建立后的字符集协商设置晚了不生效。如果目标数据库是 SQLite则更简单Conn.Protocol : sqlite-3; Conn.Database : C:\data\app.db; Conn.Connect;SQLite 不需要用户名和密码但要注意Database属性对应的是一个文件路径而非目录。如果这个路径不存在Zeos 会创建一个空库文件这种行为与 SQLite CLI 一致。很多人第一次连接 SQLite 时报“文件不存在”其实是上一行把路径写成了目录。下面给出一张参数速查表方便在源码包自带的示例工程里对照着改场景Protocol 典型写法必须参数常见坑MySQL 8mysql-5User, Password默认认证插件问题第五章单独讲PostgreSQLpostgresql-9.1HostName, Port, User端口写错会无限重试SQLitesqlite-3Database文件路径父目录不存在时静默建库FireBirdfirebird-2.5Database服务器路径需要同时指定 User/Password即使是在嵌入式模式4.2 TZQuery 参数化与事务边界避开字符串拼接的隐性风险连接配好后很多人喜欢把 SQL 直接拼字符串。Zeos 的 TZQuery 支持参数化查询而且这个参数化是推到数据库端执行的所以应该优先用参数方式既避免转义问题也降低注入风险。ZQ.SQL.Text : SELECT * FROM article WHERE category :category AND status :status; ZQ.ParamByName(category).AsInteger : 2; ZQ.ParamByName(status).AsString : published; ZQ.Open;这里参数名的冒号:是 Zeos 的占位符风格。有些驱动也支持?但用命名参数更容易维护。执行写操作时Open换成ExecSQL两者不要混用Open会尝试打开数据集并返回结果集ExecSQL只执行不关心返回行。事务控制方面Zeos 的默认行为是每个 SQL 自动提交。批量操作时建议显式包一层事务Conn.StartTransaction; try ZQ.SQL.Text : UPDATE article SET hits hits 1 WHERE id :id; ZQ.ParamByName(id).AsInteger : 100; ZQ.ExecSQL; ZQ.SQL.Text : INSERT INTO audit_log(action, user_id, ts) VALUES (hits, :user_id, NOW()); ZQ.ParamByName(user_id).AsInteger : 7; ZQ.ExecSQL; Conn.Commit; except Conn.Rollback; raise; end;注意StartTransaction之后ZQuery 内部如果发生异常如果不 Rollback 就直接释放连接数据库端的事务可能一直挂着这也是线上数据库连接被拖垮的常见原因。实践上建议在finally块里检查事务状态。更稳妥的写法是封装一个事务模板函数统一处理 Commit 和 Rollback业务代码不要再自行管理事务结尾。5. 源码编译与使用的五个常见问题排查这个环节不用“常见问题”这种空洞标题糊弄直接挑源码安装和连接阶段最高频的五个坑按现象、原因、解决三步写。5.1 组件面板不出现 Zeos Access 页签现象编译完成后IDE 里找不到 Zeos Access 组件页签或页签出现但只有一个空壳。原因旧版本的组件包残留在 IDE 的配置目录里与 6.0.12 的包 GUID 冲突或者第一次 Install 后没有真正重启 IDE。解决先到 IDE 的“组件/安装包”管理界面卸载所有名字里带 ZComponent 的旧包然后手动把源码包目录下的packages\lazarus里的zcomponent.lpk清除干净即删除编译中间文件再重新 Compile Install。多数时候不是源码问题而是 IDE 没有读取新的包配置。5.2 连接 PostgreSQL 时端口正确但仍提示连接失败现象PostgreSQL 端口监听正常防火墙已放行但 Zeos 一直报 connection refused。原因很多 PostgreSQL 实例开了 IPv6 监听而 Zeos 在部分平台默认解析到 IPv4 地址。这属于网络参数与驱动解析的边界性问题不是源码本身的逻辑错误。解决在连接代码里显式绑定协议族Conn.Properties.Add(hostaddr127.0.0.1)或直接使用hostaddr替代host强制走 IPv4。类似参数在连接字符串协议里需要参考各数据库原生命令行的参数名Zeos 支持把 JDBC 风格参数塞进 Properties 里。5.3 MySQL 8 下报 Access denied同样的账号用客户端能连现象使用 Navicat 或命令行能通过密码登录但 Zeos 连接报 access denied且有时日志里会出现 caching_sha2_password 相关字样。原因MySQL 8 默认使用 caching_sha2_password 认证插件Zeos 6.0.12 驱动支持有限很多情况下只能做兼容不能直接换认证插件为旧模式就会被拒绝。解决对开发态账号执行一条 SQL 即可ALTER USER app_userlocalhost IDENTIFIED WITH mysql_native_password BY app_pass;然后刷新权限并重连。这是社区里最常见的做法也是部署老组件连新版数据库的标准处理。注意这属于数据库账号配置的变更生产环境谨慎使用建议让 DBA 参与评估。另一个叠加因素是 SSL 握手如果客户端库没有配置正确的设置很多兼容性方案也一起失效。5.4 中文写入数据库后变成乱码或问号现象界面上显示正常入库后变成乱码读出来也是问号。ClientCodepage 设了 UTF8 也没用。原因数据库数据库端字符集与客户端不一致。MySQL 的character_set_client和character_set_connection需要统一而 Zeos 的ClientCodepage只负责告诉客户端库“我传的是 UTF8”不会去修改数据库全局配置。解决在连接建立后执行一次Conn.ExecuteDirect( SET NAMES utf8mb4 );此命令确保连接维度上的字符集协商正确。如果是 SQLite 则不存在这个问题SQLite 自身就是 UTF-8 存储。这一条经验的价值在于乱码排查要分两端先看 Zeos 传入的字节再看数据库接收时的会话设置不要一上来就怀疑组件。5.5 编译后运行提示找不到数据库客户端 DLL现象IDE 里编译全通过但程序一执行就弹窗“无法定位程序输入点”或“找不到指定模块”。原因Zeos 是动态加载客户端库的源码包不携带这些库。使用者本机的 system32 或应用目录下缺少 libmysql.dll、libpq.dll 等文件。解决把对应数据库的客户端库复制到可执行文件同一目录。这里有一个易被忽略的点x64 程序要放 64 位 DLLx86 程序要放 32 位 DLL混用会报运行时不明错误。可以把每个数据库版本所需的 DLL 单独放到C:\libs\db\目录下再用代码显式指定库路径Conn.LibraryLocation : C:\libs\db\libmysql.dll;注意某些平台的客户端库还有依赖项比如 libpq.dll 依赖 libssl一并带上才能完整。6. 用最小压测脚本验证这份源码包的可用性编译安装完成后很多人只是连接成功就收工这样并不能证明它在并发场景下没问题。我的习惯是写一段极小的压测脚本用线程开十个连接同时执行查询看有没有崩溃、连接数是否超限。function PingDatabase(AConn: TZConnection): Boolean; begin Result : False; try AConn.ExecuteDirect(SELECT 1); Result : True; except // 记录时间与错误码这里不要吞异常 end; end;然后开十个线程每个线程建立独立连接循环 100 次调用 PingDatabase在日志里记录失败次数与平均耗时。这个做法的价值在于把“驱动能不能用”和“版本稳不稳”分开验证如果十线程并发失败率偏高先检查数据库最大连接数限制而不是回退组件版本。6.0.12 的源码里有很多与连接缓存相关的细节但压测时请务必关闭连接池否则测不出真实驱动行为。最后说一个我的个人习惯每次拿到新源码包我会把编译后的包文件连同依赖库清单归档成一套部署说明存进项目仓库的 docs 目录。这样半年后客户换服务器不需要重新摸索 6.0.12 安装过程。这个版本我存了一份遇到新数据库特性先查 ZDbc 驱动目录的变更记录再动手升级组件。希望这篇笔记能帮你少走我走过的弯路。本文还有配套的精品资源点击获取
返回列表