MyDAC v5.10 源文件使用指南:Delphi MySQL 连接调试与兼容修复 简介本资源是Delphi与CBuilder开发者专用的MySQL数据库直连组件MyDAC v5.10源码包面向使用Delphi 7–2007及CBuilder开发MySQL应用的中高级开发者解决原生数据库连接性能低、依赖中间件、缺乏事务与存储过程深度支持等痛点。压缩包共1403个文件涵盖360个Pascal单元pas、146个包工程dpk/dproj、107个窗体描述dfm、81个BDS项目配置bdsproj及配套帮助文件hlp/cnt/html、许可协议rtf与构建脚本bat总大小仅1.39MB轻量但功能完备。已有167人下载学习适合需定制化适配、二次开发或深入理解MyDAC底层通信机制的开发者。用户可直接编译运行示例工程快速掌握事务处理、异步操作、触发器调用等核心能力并基于源码优化连接池、扩展MySQL 5.x特性支持真正实现零第三方依赖的纯原生数据库集成方案。1. MyDAC v5.10 源文件不是“安装包”而是 Delphi 开发者手里的数据库连接黑匣子钥匙你搜到 “MyDAC v5.10 源文件”大概率正卡在这样一个现实场景里接手一个老 Delphi 项目编译时报错Cannot find unit MyConnection或Fatal Error: Cannot open file MyDataSet.pas或者想把旧系统从 MySQL 5.6 升级到 8.0但原厂只给了个.bpl插件包没源码、没文档、一改就崩又或者你在 GitHub 上翻遍了所有叫 MyDAC 的仓库发现全是 v9.x 的新版本而你手里这份 v5.10 的 ZIP 包解压后只有.pas、.dfm、.dpk文件——它既不是 Windows 安装程序也不是 Linux RPM更不是 Docker 镜像。它是一套专为 Delphi/CBuilder 设计的原生 MySQL 数据访问组件源代码集合核心价值在于你能看见每一行 SQL 如何被封装进 TMyQuery、TMyConnection 的 VCL 层能亲手修改字符集协商逻辑、重写 SSL 握手失败时的 fallback 策略、甚至把mysql_real_connect()的调用栈打出来看参数到底传了什么。这不是给 DBA 用的运维工具而是给 Delphi 工程师用的“可调试、可定制、可降级兼容”的底层数据通道。如果你正在维护金融、医疗或工业控制类的老 Delphi 系统且数据库层必须死守 MySQL 协议而非用 ODBC 这种中间层那么 v5.10 源文件就是你唯一能真正掌控连接行为的入口——尤其当官方早已停止对它的二进制更新而你的客户服务器上跑着 MySQL 5.7.44 或 8.0.33 时。2. 解压即用不v5.10 源文件需要三步“唤醒”环境校准、包注册、单元引用链重建MyDAC v5.10 不是双击安装的软件它是一组 Delphi 源码文件其“运行”本质是让 IDE 认出这些.pas是合法单元并让编译器能把它们链接进你的.exe。这过程远比make install复杂因为涉及 Delphi 版本兼容性、RTL 版本对齐、以及最关键的——BPL 包依赖树的显式声明。v5.10 发布于 2012 年左右原生支持 Delphi 2007–2010但实测在 Delphi 10.4 Sydney 和 11 Alexandria 上也能工作前提是手动绕过几个 RTL 变更点。下面三步是唤醒它的最小可行路径跳过任意一步都会导致“找不到单元”或“Linker Error: Unresolved external”。2.1 环境校准确认 Delphi 版本与 RTL 兼容边界v5.10 的源码大量使用AnsiString、PAnsiChar和{$IFDEF UNICODE}条件编译但它不支持 Delphi XE2 及之后默认开启的 Unicode RTL。直接在 Delphi 10.4 中打开.dpk会报Undeclared identifier: AnsiString。解决方法不是升级 MyDAC而是降级 RTL 兼容性// 在你的项目 .dpr 文件顶部紧贴 program 声明下方插入 {$IFDEF VER230} // Delphi XE2 的 RTL 版本号 {$DEFINE DELPHI_XE2_OR_LATER} {$ENDIF} {$IFDEF DELPHI_XE2_OR_LATER} {$UNDEF UNICODE} {$IFDEF WIN32} {$DEFINE ANSISTRING_SUPPORTED} {$ENDIF} {$ENDIF}提示VER230是 Delphi XE2 的编译器版本常量XE3 是VER24010.4 是VER320。v5.10 能跑通的最高 Delphi 版本是 10.4但必须关闭 Unicode RTL。不要尝试在 11 AlexandriaVER340上硬扛——RawByteString和UTF8String的语义已彻底改变强行编译会导致运行时内存越界。2.2 包注册用 .dpk 编译 BPL而非直接引用 .pasv5.10 提供多个.dpk文件如MyDacD14.dpk对应 Delphi 2010但它们不是拿来双击安装的。正确流程是打开 Delphi IDE →Component → Install Packages…点击Add…→ 导航到解压目录下的Source\D14\MyDacD14.dpkD14 表示 Delphi 2010勾选Install into IDE→ 点击 OKIDE 会自动编译该.dpk生成MyDacD14.bpl和MyDacD14.dcp关键点在于.dpk中的requires列表必须与你的 Delphi 版本匹配。例如MyDacD14.dpk的 requires 是requires rtl, vcl, vclx, dbrtl, adortl, dsnap;如果你用的是 Delphi 10.4vclx和dsnap已被移除必须手动删掉这两行否则编译失败。删掉后requires应为requires rtl, vcl, dbrtl, adortl;参数说明rtl是运行时库vcl是可视化组件库dbrtl是数据库运行时adortl是 ADO 支持库MyDAC 内部用它做部分元数据操作。少一个IDE 就无法加载设计时组件多一个不存在的包编译器直接报错。2.3 单元引用链重建从 uses 到 Search Path 的全链路打通即使 BPL 安装成功你的 Form 单元仍可能报Cannot find unit MyConnection。这是因为 Delphi 的单元查找顺序是当前工程目录Search Path项目选项中设置BPL 的 DCU 目录仅限设计时RTL/VCL 源码目录v5.10 的.pas文件默认放在Source\D14\下而.dpk编译时并不会自动把该路径加进 Search Path。必须手动配置右键项目 →Options → Delphi Compiler → Search Path在Unit Search Path中添加$(MYDAC_ROOT)\Source\D14;$(MYDAC_ROOT)\Source\Common;$(MYDAC_ROOT)\Source\Win32$(MYDAC_ROOT)是你解压 MyDAC 的根目录如C:\MyDAC_v510然后在你的主窗体.pas文件中uses子句必须显式列出 MyDAC 单元且顺序不能错uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, // ↓ MyDAC 单元必须放在 VCL 单元之后且按依赖顺序排列 ↓ MyClasses, // 基础工具类所有 MyDAC 单元都依赖它 MyConst, // 常量定义 MyTypes, // 类型定义 MyConnection, // 核心连接类 MyDataSet, // 数据集类 MyQuery; // 查询类逻辑说明MyClasses定义了TMyCustomDataSet等基类MyConnection继承自它MyDataSet又继承自MyConnection。如果MyDataSet写在MyClasses前面编译器根本不知道TMyCustomDataSet是什么类型直接报错。这个顺序不是约定俗成而是源码中interface uses的硬依赖关系决定的。3. 编译通过 ≠ 运行正常v5.10 连接 MySQL 5.7/8.0 的三大握手陷阱MyDAC v5.10 的源码里MySQL 协议握手逻辑固化在MyConnection.pas的TMyConnection.ConnectToServer方法中。它默认按 MySQL 4.1 协议实现而 MySQL 5.7 默认启用caching_sha2_password插件8.0 更是强制要求 TLS 1.2。这就导致编译成功、BPL 加载成功、TMyConnection创建成功但一调Open就卡死或报Access denied for user。这不是密码错了而是协议层根本没谈拢。以下是三个必须手动修补的握手陷阱每一条都来自真实客户的生产环境翻车记录。3.1 密码加密算法不匹配从mysql_native_password到caching_sha2_password的降级开关MySQL 5.7.21 新建用户默认用caching_sha2_password而 v5.10 只认识mysql_native_password。现象是连接字符串写对了用户名密码也对但TMyConnection.Open抛出异常Authentication plugin caching_sha2_password cannot be loaded。原因在于 v5.10 的MyConnection.pas第 2187 行if (ServerVersion 4.1.1) and (Length(Scramble) 20) then Result : CalcPassword(Password, Scramble) else Result : OldCalcPassword(Password, Scramble);这段代码只处理mysql_native_password的 scramble20 字节对caching_sha2_password的 12 字节 scramble 直接返回空密码。解决方法不是重写 SHA256 逻辑v5.10 没这能力而是强制服务端用老插件-- 在 MySQL 服务器上执行需 root 权限 ALTER USER your_user% IDENTIFIED WITH mysql_native_password BY your_password; FLUSH PRIVILEGES;参数说明IDENTIFIED WITH mysql_native_password显式指定认证插件FLUSH PRIVILEGES立即生效。不要用SET PASSWORD它在 5.7.6 后已被弃用。3.2 SSL 握手失败禁用 TLS 或注入自签名证书路径MySQL 8.0 默认require_secure_transportONv5.10 的TMyConnection.SSL属性却只支持 OpenSSL 0.9.8而现代系统装的都是 OpenSSL 1.1.1。现象是连接超时Wireshark 抓包显示 Client Hello 后无 Server Hello。原因在于MyConnection.pas的InitSSL方法调用SSL_library_init()时新版 OpenSSL 返回SSL_ERROR_SSL。最稳方案是关闭 SSL测试环境或指定证书路径生产环境// 在 TMyConnection.OnConnect 事件中或 Open 前 MyConnection.SSL : True; MyConnection.SSLMode : smRequired; MyConnection.SSLCAFile : C:\certs\ca.pem; // CA 证书路径 MyConnection.SSLCertFile : C:\certs\client.pem; // 客户端证书 MyConnection.SSLKeyFile : C:\certs\client.key; // 客户端私钥注意SSLCAFile必须是 PEM 格式且ca.pem里不能包含多余空行或 UTF-8 BOM。v5.10 的 SSL 加载器会因 BOM 报SSL_CTX_use_certificate_chain_file failed。3.3 字符集协商崩溃UTF8MB4 与 UTF8 的字节长度误判MySQL 5.5.3 默认字符集是utf8mb4而 v5.10 的MyConnection.pas在GetServerCharset方法中硬编码了utf8的字节长度为 3case CharsetID of 33: Result : utf8; // MySQL 的 utf8 字符集 ID 是 33 255: Result : utf8mb4; // utf8mb4 的 ID 是 255但 v5.10 没处理 else Result : latin1; end;结果是当服务器返回 charset ID 255 时Result被设为latin1后续所有AnsiString转换都乱码。补丁只需两行case CharsetID of 33: Result : utf8; 255: Result : utf8mb4; // ← 新增这一行 else Result : latin1; end;血泪经验这个 bug 导致某银行客户报表导出中文全是问号排查三天才发现是字符集 ID 映射表漏了。v5.10 源码里所有CharsetID判断都要扫一遍MyDataSet.pas的GetFieldData方法里也有同样问题。4. 避坑v5.10 源文件开发中 5 个高频翻车点及现场急救指南MyDAC v5.10 的源码不是“开箱即用”它是把 Delphi 工程师扔进 MySQL 协议深水区的救生圈——但救生圈本身有破洞。以下 5 条是我在 7 个遗留系统迁移项目中亲手填过的坑每一条都附带现象、根因和一行救命命令/代码。4.1 现象编译通过运行时报Access violation at address XXXX in module MyDacD14.bpl原因v5.10 的MyDataSet.pas中TMyDataSet.InternalSetFieldData方法未检查Field.DataSize是否为 0当字段为TEXT类型且值为空时Move函数 memcpy 0 字节地址导致 AV。解决在InternalSetFieldData方法开头加防护if (Field.DataSize 0) or (Value nil) then Exit;4.2 现象TMyQuery.Open成功但RecordCount返回 -1First/Last无效原因MySQL 5.7 默认sql_modeSTRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTIONv5.10 的TMyQuery.GetRecordCount调用SELECT FOUND_ROWS()前未执行SELECT SQL_CALC_FOUND_ROWS * FROM ...FOUND_ROWS() 返回 0。解决不用RecordCount改用TMyQuery.RecordCount : TMyQuery.RecordCount触发缓存或手动执行MyQuery.Close; MyQuery.SQL.Text : SELECT SQL_CALC_FOUND_ROWS * FROM your_table; MyQuery.Open; MyQuery.SQL.Text : SELECT FOUND_ROWS(); MyQuery.Open; ShowMessage(MyQuery.Fields[0].AsString); // 实际行数4.3 现象TMyConnection连接池复用时第二个连接报Commands out of sync原因v5.10 的连接池TMyConnectionPool未重置mysql_thread_safe状态多线程下mysql_real_query调用顺序错乱。解决禁用连接池改用单连接 TMyConnection.Clonevar NewConn: TMyConnection; NewConn : MyConnection.Clone as TMyConnection; NewConn.Open;4.4 现象TMyDataSet.Locate在utf8mb4字段上永远返回 False原因MyDataSet.pas的CompareStrings方法用AnsiCompareStr比较 UTF8 字节流但utf8mb4的四字节字符如 emoji被截断为三字节比较必然失败。解决强制转为 Unicode 比较function CompareStrings(const S1, S2: string): Integer; begin Result : CompareText(S1, S2); // ← 用 CompareText 替代 AnsiCompareStr end;4.5 现象TMyQuery执行含中文的INSERT语句数据库里存成????原因v5.10 的TMyQuery.Prepare方法未在mysql_stmt_prepare前调用mysql_set_character_set预编译语句默认用 latin1。解决在TMyQuery.BeforeOpen事件中手动设字符集MyQuery.Connection.SetCharset(utf8mb4);提示SetCharset是TMyConnection的公开方法调用它会执行mysql_set_character_set(conn, utf8mb4)确保后续所有语句包括预编译都用正确字符集。5. 源码级调试实战用 v5.10 源文件定位 MySQL 连接超时的真实根源当你面对一个“连接偶尔超时、重启服务就恢复”的玄学问题时官方文档只会告诉你“调大wait_timeout”但真实瓶颈往往藏在 MyDAC 的 socket 层。v5.10 源文件的价值就在于让你能亲手把MyConnection.pas的ConnectToServer方法变成一个实时监控探针。下面这个技巧我已在三个客户现场用它揪出 DNS 解析延迟、防火墙 ICMP 丢包、以及 MySQL 服务器max_connections耗尽的真实原因。5.1 在ConnectToServer中注入毫秒级时间戳日志打开MyConnection.pas找到TMyConnection.ConnectToServer方法。在mysql_real_connect调用前后插入高精度计时uses Winapi.Windows; // ← 确保 uses 里有这个 function GetTickCount64: Int64; external kernel32.dll; procedure TMyConnection.ConnectToServer; var StartTick, EndTick: Int64; begin StartTick : GetTickCount64; // 原有的 mysql_real_connect 调用保持不变 FHandle : mysql_real_connect(FHandle, PAnsiChar(Host), PAnsiChar(UserName), PAnsiChar(Password), PAnsiChar(Database), Port, PAnsiChar(Socket), ClientFlag); EndTick : GetTickCount64; // 记录日志用 OutputDebugString 便于 Sysinternals DbgView 捕获 if (EndTick - StartTick) 3000 then // 超过 3 秒记为慢连接 begin OutputDebugString(PAnsiChar(Format(MyDAC Connect Slow: %d ms, Host%s, User%s, [EndTick - StartTick, Host, UserName]))); end; end;逻辑说明GetTickCount64返回毫秒级时间戳比Now或GetTickCount更准。OutputDebugString不写文件、不占磁盘所有 Windows 调试器包括 DbgView都能实时捕获。这样你就能看到是mysql_real_connect调用本身卡住网络层问题还是它返回后FHandle初始化卡住MyDAC 内部逻辑问题。5.2 关键参数表v5.10 连接超时链路上的 4 个可调阀门参数位置参数名默认值修改方式影响范围调试建议TMyConnection对象ConnectTimeout0无限MyConnection.ConnectTimeout : 5000;mysql_real_connect调用超时设为 5000若日志显示Connect Slow且时间 ≈5000ms说明是网络不可达MyConnection.pas源码SO_RCVTIMEO/SO_SNDTIMEO未设置在ConnectToServer中setsockopt设置TCP socket 接收/发送超时若Connect Slow时间随机如 200ms/1200ms/800ms说明是中间设备防火墙/NAT丢包MySQL 服务器wait_timeout288008小时SET GLOBAL wait_timeout300;连接空闲超时若日志显示首次连接快、后续连接慢且mysqladmin proc显示大量Sleep状态说明连接池复用时被服务器踢掉TMyConnectionPoolMaxIdleTime3000005分钟MyPool.MaxIdleTime : 60000;连接池中空闲连接存活时间若Connect Slow总发生在连接池取连接时说明MaxIdleTimewait_timeout取到的连接已被服务器关闭5.3 用 Wireshark 验证抓包看三次握手与 SSL Client Hello光有日志不够必须验证是哪一层出问题。启动 Wireshark过滤ip.addr your.mysql.server.ip and tcp.port 3306然后触发一次TMyConnection.Open如果只有 SYN 包发出无 SYN-ACK 返回→ DNS 解析失败或路由不通检查ping your.mysql.server.ip如果有 SYN-ACK但无后续 ACK→ 防火墙拦截检查telnet your.mysql.server.ip 3306是否通如果有完整 TCP 握手但无 MySQL Protocol 包→mysql_real_connect调用失败查 MyDAC 日志中的Connect Slow时间如果有 MySQL Protocol 包但卡在Client Hello后→ SSL 版本不匹配v5.10 只支持 TLS 1.0MySQL 8.0 默认 TLS 1.2我的习惯每次客户报“连接不稳定”我第一件事就是用 DbgView 挂着看MyDAC Connect Slow日志第二件事是 Wireshark 抓包对比。90% 的问题要么是ConnectTimeout设太小误报超时要么是wait_timeoutMaxIdleTime连接池取到废连接。v5.10 源文件给我的不是“修 bug 的能力”而是“把黑匣子变成透明管道”的底气——我不再靠猜而是靠证据说话。希望帮到你。本文还有配套的精品资源点击获取