资讯动态

MyDAC v5.10源文件包:Delphi直连MySQL的底层原理与避坑实战

发布时间:2026/10/9 13:52:47 来源:尧图企业网站定制
简介MySQL Data Access ComponentsMyDACv5.10源文件包面向使用Delphi 7至2007及CBuilder进行MySQL数据库开发的程序员提供一套不依赖第三方中间件、可直接与MySQL服务器通信的数据库访问组件方案。包体共1403个文件、约1.39MB以pas源码、dpk包工程、res资源、dfm窗体定义、cfg编译配置及bdsproj工程文件构成兼顾cpp、dpr、bat等辅助构建文件便于按需定制编译或排查集成问题。同时附有MyDac.hlp帮助文档、FAQ.html常见问题、History.html版本记录与License.rtf许可说明可离线查阅API细节与授权范围。已有167人浏览学习适合需要深入理解MyDAC内部实现、做二次扩展或离线查阅资料的中高级Delphi/CBuilder开发者。1. MyDAC v5.10 源文件包为什么还要研究一套老掉牙的 MySQL 直连组件接手过用 Delphi 维护的老项目数据库从 MySQL 5.5 一路升到 8.0原来依赖 ODBC 的连接在部署机上少 dll、缺驱动最后换成 MySQL Data Access ComponentsMyDACv5.10 的源文件包自己编译一次彻底消停。这套资源不包含安装程序是完整源码可以编译出运行期库和设计期包让组件直接出现在 IDE 面板里。它的核心价值在 Direct 模式不走 ODBC不走 libmysql.dll用组件自己实现的客户端协议直连 MySQL 服务器。适合三类人维护老 Delphi 项目的开发者、想研究 MySQL 握手协议实现的人、被 ODBC 部署问题折磨到想换方案的人。下面把架构、编译、连接参数、踩坑记录一次讲完。2. 组件架构与 Direct 连接协议先弄清它和 ODBC 的本质差别2.1 核心组件族从 TMyConnection 到 TMyLoader 的分工MyDAC 源文件包里不是孤立的连接控件而是一整套组件族核心由五类组件配合工作。第一次拆包的人容易只看 TMyConnection实际工程里它们的职责差异很大在不合适的场景用错组件性能差别不是线性而是数量级。组件类型职责TMyConnection非可视物理连接管理、事务、连接池参数TMyMetaData非可视读取表结构、约束、存储过程元数据TMyQuery数据集执行 SQL 并返回结果集操作习惯与 TQuery 一致TMyScript非可视执行多条 SQL 脚本适合初始化表结构TMyLoader非可视客户端批量导入数据替代逐行 Insert我一般这样选型只有查询走 TMyQuery 就够了需要跑建表脚本或一次性初始化数据TMyScript 更合适超过几万行写入不要用循环 InsertTMyLoader 才是正路。曾经在一个库存导入项目里见过逐条 Insert 写了两千多条循环导入六万条记录花了近三分钟切成 TMyLoader 后压在五秒内。为什么要自己研究源码而不是只用安装版因为源文件包的价值在于可以查看组件在直连模式下的一次完整生命周期。比如 TMyQuery.Open 的过程实际包含分配语句句柄、发送查询报文、解析列定义、逐行读取结果集这些动作对应着 TCP 流上的具体字节。跟着源码走一遍比看文档猜行为高效得多。TMyQuery 和 TQuery 的使用习惯很像但它多了 Prepare 和参数绑定。传参时推荐这样写var Qry: TMyQuery; begin Qry : TMyQuery.Create(nil); try Qry.Connection : Conn; Qry.SQL.Text : SELECT id, name FROM sku WHERE status :st; Qry.Params[0].AsInteger : 1; Qry.Open; // 读取字段 finally Qry.Free; end; end;这段代码先用 Connection 属性把查询挂到已建立的连接上再用 :st 占位符避免拼接字符串最后用 Open 获取结果集。如果执行的是 INSERT、UPDATE 这类不返回结果集的语句要用 ExecSQL 而不是 Open否则会抛“结果集为空”的异常。Params 在 v5.10 里支持序号访问也支持按名称访问我更推荐按名称写避免 SQL 调整后字段顺序变化踩到暗坑。2.2 Direct Mode 协议栈绕过客户端库的收益与代价MyDAC 和其他连接组件最大的区别是 Direct Mode直连模式。传统 ODBC 的调用链是应用程序 → ODBC Driver Manager → MySQL ODBC Driver → 服务器。MyDAC 直连模式把这条链砍成应用程序 → MyDAC 运行时 → 服务器连接握手、认证报文、结果集解析全部在运行时内部完成不依赖系统是否安装 libmysql.dll、myodbc.dll 这类外部文件。选择直连等于放弃官方客户端库提供的部分兼容性。我在实际部署里体会到两个直接收益一是打包的时候不用连带三个 dll单文件输出就能跑二是机器上装了什么样乱七八糟的客户端版本都不再影响程序行为。代价是协议侧的新特性必须等组件升级v5.10 发布的年代远早于 MySQL 8.0显然不会认识 MySQL 8 的新认证插件这就是后面避坑章节里连接失败的根源。从协议层面看直连模式底层做的工作是这样的先通过 TCP 连上服务器的 3306 端口服务器返回握手包其中包含协议版本、服务器版本字符串、连接 ID、认证插件数据客户端回传认证信息用户名、密码、数据库名服务器返回 OK 包就进入命令阶段否则回 ERR 包并带错误码。抓包时注意MySQL 握手包里的第一个字节是协议版本老版本报文里很多字段是零值这些在新版本协议里已经废弃或改变含义。v5.10 源码里的报文解析函数对未知字段的处理方式是忽略而不是报错这解释了为什么它能连上新版本、却认不出新认证方式。MyDAC 源文件包值得研究的地方就是它用 Object Pascal 完整实现了一遍这个报文流程。这里面包含了分包、粘包、压缩、SSL 加密分支读源码是学习 MySQL 客户端协议很直接的教材。2.3 源文件包目录结构拆包后第一眼该看什么源文件包解压后不要急着把整个目录塞进 IDE先看结构。常见的布局是这样$ tree -L 2 -d . ├── Source │ ├── Delphi7 # 对应老版本 IDE │ ├── Delphi2009 # 按编译器版本拆分的子目录 │ ├── XE │ └── ... ├── Demos │ ├── Connection │ ├── DataSet │ ├── MyLoader │ └── MetaData └── Docs关键点在 Source 下的子目录作者按编译器版本维护不同分支原因是 Object Pascal 的语法版本、RTL 接口在不同年代有差异。你用的 IDE 版本决定了必须选哪套子目录选错会在编译阶段遍地报错。Demos 目录则是一手使用范例我会在看文档前先翻 Demos 里的工程文件因为示例代码的写法就是组件默认行为最直观的展示。Docs 里的帮助文档是 .chm 还是 .txt 不重要重要的是其中关于 Options 属性的说明那是调节组件行为的集中地。第一次编译的时候我犯过一个错误直接打开 Source 根目录的 .dpk 文件结果 IDE 报错找不到一堆单元文件。后来才发现 .dpk 是入口真正对应版本的源代码在子目录里。因此第二步操作要记住先确认自己 IDE 的编译器版本再进入对应子目录编译不要在根目录里硬碰。还有一个小技巧把 Source 子目录整个加入 IDE 的浏览路径这样按住 Ctrl 点击组件方法可以直接跳进源码调试组件内部逻辑时非常顺手。这套资源是商业组件的源文件版本适合有授权基础的技术团队内部二次开发也适合协议研究者通读报文处理代码。3. 源码编译与安装从 IDE 版本匹配到包路径配置3.1 编译前置条件确认编译器版本、输出目录与库路径把源文件包变成 IDE 面板里能拖出来的组件前置条件出在三个地方IDE 的编译器版本、输出目录、库路径。编译器版本直接决定用 Source 下哪个子目录输出目录决定编译产生的 .dcu、.bpl 文件落在哪里库路径决定 IDE 在编译期能不能搜到这些单元。我可以先列一个自查清单打开 IDE 的关于对话框确认编译器版本编号和 Source 子目录命名对齐。规划一个统一输出目录比如 MyDACOutput不要让 .dcu 散落在源码目录里。记录 IDE 的库路径配置位置后面要把源码子目录加进去。检查本机是否残留其他版本的 MyDAC 组件包旧包不卸载干净新装组件会引起“类已注册”之类冲突。这里最容易翻车的不是版本选错而是残留包冲突。之前在一台测试机上装了旧版组件没卸载又编译新版IDE 启动时直接弹 duplicated TMyConnection 的报错排查了很久才发现是旧包没清干净。所以前置检查要先把 IDE 的组件包列表打开卸载掉同名的旧包再做新编译。编译行为在 IDE 大版本之间有差异老包文件里可能包含一些已废弃的编译指令。遇到不认识的 {$ ... } 指令先查询当前版本是否还支持不支持就注释掉但 {$R xxx.dcr} 这类资源引用不能乱注释去掉会导致组件在面板上没有图标。3.2 编译运行期库与安装设计期包一份可以照着做的步骤确认完前置条件按这套走不会出大错。先编译运行期包再安装设计期包顺序固定因为设计期包依赖运行期包导出的单元。# 1. 进入对应编译器版本子目录以 XE 子目录为例 $ cd Source/XE # 2. 确认目录下有两个核心包文件 $ ls *.dpk # MyDAC.dpk # 运行期包 # dclMyDAC.dpk # 设计期包dcl 前缀标识 # 3. 查看包文件头确认引用的源文件都在 $ grep -c MyConnection.pas MyDAC.dpk包文件内容可以看成一组单元列表和编译选项的集合。.dpk 文件里用 contains 列出要编译的单元用 requires 声明对外部包的依赖。v5.10 的 requires 一般只依赖 RTL 核心包第三方依赖少是它能在老环境里生存的重要条件。在 IDE 里打开 MyDAC.dpk先做一次 Build。Build 成功后打开 dclMyDAC.dpk执行 Install 操作组件会自动注册到面板。如果安装时提示某单元找不到回上一步把源子目录加入 IDE 库路径再重新打开包。我在第一次操作时没有把源码子目录加进库路径结果 IDE 找不到 MyConnection.pas 等实现单元报错一片红。加库路径这个动作看起来基础却是这套流程里最容易被忽略的一环。库路径是给编译器和包管理器查找单元、源码用的不在路径里就必须让 .dpk 文件和源文件同级所以偷懒的办法是直接把 .dpk 放到源文件所在子目录但我仍然建议用库路径而不是移动文件避免 Demo 工程里的相对路径失效。验证安装是否成功最直接的方法是新建一个工程切换到组件面板查找 MyDAC 分组下的控件。能看到 TMyConnection、TMyQuery 等组件图标说明运行期库编译成功并且设计期包安装生效。如果图标缺失优先查设计期包里的 .dcr 资源引用这一步在后面的避坑章节会展开讲。3.3 设计期与运行期分离安装完还要搞明白的两类包组件包里一定有两类后缀不同的包文件这是理解整个安装过程的关键。运行期包MyDAC.bpl承载实际代码程序编译运行就要它设计期包dclMyDAC.bpl只在 IDE 设计界面时发挥作用比如把组件注册到面板上。安装设计期包时它会要求运行期包不缺失而普通项目编译只需要把运行期包加入工程即可。程序发布时还要决定怎么带运行期。有两种选择一是项目里不再依赖 BPL而是引用 .dcu 静态编译输出单个 exe二是保留 BPL发布时把 MyDAC.bpl 放在 exe 同目录。前者适合要交付单文件的场景后者适合多个程序共享一份运行时。我倾向于发布时用静态编译因为目标机器上的运行环境不可控BPL 版本一旦与其他程序冲突排查成本很高。发布时如果选择静态编译要留意 IDE 项目选项里“Build with runtime packages”复选框。勾选后程序运行还需要 BPL 文件取消勾选则把组件代码编进 exe体积会变大几 MB但部署目录里只放一个 exe 和配置文件就够了。设计期包不需要发布只装在开发机器上。区分两类包很简单文件名带 dcl 前缀的是设计期包不带的是运行期包。这个命名习惯在组件世界里延续了很多年看懂它你就不会在下发素材里乱猜了。4. 连接与查询实战从最小连接串到生产级参数4.1 最小连接串Server、Port、Database 与账号密码的取舍写完组件安装先解决最现实的“怎么连上”。MyDAC 的连接参数可以通过属性面板设置也可以在运行期用 Params 赋值。最小可用的连接配置只需要四个参数服务器地址、端口、库名、账号密码。端口不写默认是 3306但显式写出来更符合工程习惯。var Conn: TMyConnection; begin Conn : TMyConnection.Create(nil); try Conn.Server : 192.168.1.25; Conn.Port : 3306; Conn.Database : erp_db; Conn.Username : app_user; Conn.Password : Secret; Conn.Connect; // 连接成功后做业务操作 finally Conn.Free; end; end;这段代码先创建连接对象再逐个赋值服务器信息和账号最后 Connect。需要注意 Database 可以不填但很多 SQL 依赖当前库名解析表名不填就会要求每张表都带库名前缀后期改起来麻烦。Connect 是同步调用连接失败会抛出异常建议在 try except 里捕获并记录错误码因为 MySQL 的错误码能直接映射到服务器端日志排查时会省很多事。连接成功后有个容易忽略的细节连接对象是否已经处于自动提交状态。MyDAC 默认开启自动提交也就是每条 SQL 立即生效如果你要批量写入再统一回滚这里必须做后面提到的事务切换否则中途出错数据散落。4.2 连接池与字符集参数并发和乱码的根源生产环境里连接不复用是性能杀手。MyDAC 提供连接池能力相关参数集中在 Pooling 结构里。最常用的配置是打开池、设定上限、设置超时Conn.Options.Pooling : True; Conn.Options.Pooling.MaximumItems : 30; Conn.Options.Pooling.ConnectionLifetime : 300;Pooling 为 True 表示连接关闭后不物理断开而是归还池中MaximumItems 决定池中最多保留多少空闲连接ConnectionLifetime 是连接最长存活秒数超过后会被清理重建。这里有个权衡池太小高并发时还是会频繁建立新连接池太大空闲期会占住数据库连接数。实际经验是从 20 起步做压测观察数据库最大连接数占用再调。字符集参数是另一个高频事故点。v5.10 时代默认字符集与服务器的通信字符集可能不一致最常见的就是写入中文正常、读出来乱码或者反过来。处理方案是在连接建立前显式指定Conn.Options.Charset : utf8mb4;先把这行加上再测一次原有业务。utf8mb4 与 utf8 的区别在于对 emoji 和生僻字的支持MySQL 5.5.3 以后推荐 utf8mb4。如果服务器端表结构用的是 utf8连接用 utf8mb4 也能正常工作反过来则可能因为字符放不下报错。需要注意字符集设置的是连接层的传输编码表字段本身的字符集是另一码事两层不一致才是乱码的真正根源。排错时按“服务器字符集、连接字符集、应用显示字符集”三层核对。注意连接字符集和表字段字符集是两层概念先分别确认再排错不要一上来就改 ALTER TABLE。4.3 事务、批处理与 TMyScript减少往返的三种写法网络往返是数据库瓶颈里最容易被低估的一项。一次 Insert 一次往返一万条就一万次。MyDAC 提供三种减少往返的方案显式事务合并提交、TMyScript 多语句脚本、TMyLoader 批量装载。按场景选不要只认一种。显式事务最常见的写法Conn.StartTransaction; try Qry1.ExecSQL; Qry2.ExecSQL; Conn.Commit; except Conn.Rollback; raise; end;StartTransaction 关闭自动提交Commit 统一落盘异常时 Rollback 撤销全部变更。这里的优势不只是能回滚更在于把多条 SQL 的落盘合并成一次组提交减少磁盘刷盘次数。要注意事务不能嵌套如果上游代码已经开启事务这里再 Start 会报错。TMyScript 适合初始化脚本、批量 DDL、迁移语句直接把多条 SQL 一次发给服务器var Script: TMyScript; begin Script : TMyScript.Create(nil); try Script.Connection : Conn; Script.SQL.Text : CREATE TEMPORARY TABLE t1 (id INT);#13#10 INSERT INTO t1 VALUES (1);#13#10 SELECT * FROM t1;; Script.Execute; finally Script.Free; end; end;TMyScript 会把文本里的语句逐条发送执行注意每条语句之间要分隔清楚最后一条是查询时结果不会像 TMyQuery 那样自动打开需要配合下游重新查询或单独查。分隔符问题我在脚本里吃过大亏花了好几个小时才发现是中间语句没加分号导致整段被当成一条 SQL 发送。凡是多条语句塞进同一个文本块的场景分号规范必须当作硬性纪律。5. MyDAC v5.10 避坑指南五个现场踩过的坑5.1 现象MySQL 8 下连接直接报认证插件不支持换了 MySQL 8 服务器后v5.10 连接时报错“Authentication method caching_sha2_password not supported”之类的拒绝信息程序没法连库。原因是 MySQL 8 默认把新建用户的认证插件改成了 caching_sha2_password而 v5.10 年代的客户端协议实现不认识这个新握手分支。解决步骤是在服务器端把相关账号改回 mysql_native_passwordALTER USER app_user% IDENTIFIED WITH mysql_native_password BY Secret;如果服务器对默认认证插件有全局要求需要改 my.cnf 的 default_authentication_plugin改完重启。从项目长期维护角度看这只是临时方案组件或者连接方案升级才是根治。如果走客户端库方案代替直连模式则要选择支持该认证插件的驱动版本两边版本要匹配。5.2 现象中文写入正常读出来一片乱码程序里插入的中文在数据库客户端里看是好的但在程序界面上读出来乱码。原因是连接层字符集和表字符集不一致最常见是默认连接用 latin1 或 utf8客户端界面按系统区域解释两边错位。解决分两步。先确认当前会话字符集SET NAMES utf8mb4;再把连接组件参数固定为 utf8mb4并在建表时统一表字符集。我在项目里试过只改连接参数表字段还是 utf8大部分中文字符没问题但碰到个别生僻字直接变成问号。所以正确姿势是表和连接都改成 utf8mb4。改表数据的迁移要先备份在一张测试表上验证完再全库执行不要在生产上直接跑 ALTER TABLE。5.3 现象64 位进程随机崩溃堆栈指向 MyDAC 内部程序从 32 位切到 64 位后在高负载或大数据量解析时随机崩溃堆栈指向 MyDAC 单元内部。原因是老版本源码里可能存在指针类型截断——32 位下 Pointer 和 Integer 等宽64 位下宽度翻倍代码里若有 Pointer 转 Integer 再转回 Pointer 的操作必然丢失高位。解决办法是查看 v5.10 源码中网络缓冲区、对象列表相关单元的整数类型声明把 Integer 改成 NativeInt 重新编译。这类问题在升级到 64 位编译环境时高发碰到随机崩溃不要先怀疑自己的业务代码先排查组件源码里的基础类型。老项目换 64 位编译器之前先把源码静态扫描一遍指针类型能省掉后面一整周的排查时间。5.4 现象新版 IDE 编译源包报错找不到资源文件用新版 IDE 打开 v5.10 源包编译时报找不到 .dcr 资源文件。原因是 .dcr 是设计期图标资源老版本放在相对路径下新版编译器对资源编译和搜索的路径规则有调整。解决方法是找到包文件里对 .dcr 的引用给 dcl 包补全资源路径或者直接用源码目录里已有的 .dcr 文件。这个坑不复杂但在团队环境里很多人卡在第一步就不想再碰源码实际补一跳路径就解决。建议把补丁做法记录在自己的项目文档里下次换机器能省半个小时。5.5 现象浮点字段与日期显示和原生客户端不一致查询到的 DECIMAL 或 DOUBLE 字段在 TMyQuery 里显示为近似值或者日期变成 00:00:00。原因是数据集组件在字段类型推断时对 MySQL 十进制数和日期时间的映射有默认逻辑v5.10 的映射表和后来 MySQL 版本的返回类型存在偏差。解决方式是在 SQL 里显式转换比如把 DECIMAL 转成字符串再读或者用 CAST 指定类型SELECT CAST(price AS CHAR) AS price_str FROM goods WHERE id 1;这个方案不需要改组件源码兼容性最好。日期问题优先检查服务器的 time_zone 设置和连接参数里是否指定了时区组件端多用 FormatDateTime 固定格式不要依赖组件默认的显示约定。6. 替换组件前的验证清单把迁移跑成调试习惯6.1 基线对比同一查询在两个方案下的结果动手改代码前先建立基线。记录当前系统用的连接方式、连接串、典型查询的耗时、结果集行数然后在新方案里执行同一个 SQL 对照。不要只对比耗时结果集内容也必须逐字段核对数据类组件迁移时最常见的隐蔽问题是若干边界值的显示差异。我通常建一张基线表SQL、行数、关键字段值、耗时两个方案各填一列跑完再改代码。6.2 追踪与日志用 Trace 机制定位组件内部行为别把组件当黑匣子。MyDAC 提供了 Trace 机制打开后组件会输出连接建立、SQL 发送、错误返回等关键节点调试连接问题时比瞎猜快得多。做法是在连接对象上打开追踪开关把事件文本写入文件复现问题后直接看最后一次交互Conn.Options.Trace : True; Conn.Options.TraceFlags : [tfConnect, tfExecute];这段代码在连接成功后打开执行级追踪后续 SQL 与 MySQL 之间的交互会被记录。线上环境不建议长期开启追踪会引入额外开销排查完成后立刻关闭。6.3 从 ODBC 迁移到 MyDAC 的等价替换速查换连接组件不是翻译代码而是要按能力替换调用点。常用的映射关系如下原 ODBC 调用MyDAC 对应写法SQLDriverConnect 连接TMyConnection.Server / ConnectSQLExecDirect 执行TMyQuery.ExecSQLSQLFetch 取结果TMyQuery.Open 后字段访问SQLEndTran 提交回滚StartTransaction / Commit / Rollback批量参数绑定TMyLoader.LoadFromDataSet确信把连接串参数、字符集、事务边界三处都对应上迁移工作就完成了七成。最后一个建议是迁移后保留旧代码分支一个版本周期随时可以对比回退。从那以后我每次替换数据库连接组件都强制自己先跑一遍基线对比和 Trace 日志确认行为一致再动代码这个习惯帮我挡掉了至少两次潜在的生产事故。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑