ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MyDAC源码包深度解析:Delphi直连MySQL协议与认证修复

MyDAC源码包深度解析:Delphi直连MySQL协议与认证修复 简介这是一份 MyDACMySQL Data Access Components5.00.1.7 的完整源代码压缩包解决 Delphi、Delphi for .NET、CBuilder 与 Kylix 开发者直连 MySQL 服务器、绕过复杂中间层的数据库访问问题。相较于标准 MySQL 连接方案MyDAC 提供更快捷、更整洁的组件化开发方式适合有 Delphi/CBuilder 基础、希望用原生组件替代 BDE 的桌面数据库应用开发者。压缩包约 2.1MB共 1297 个文件以 348 个 PAS 单元源码为核心并附带 DPK、BDSProj、CFG、DFM、BMP 等工程与资源文件涵盖组件注册、界面资源和多版本工程配置便于在多种 IDE 版本中编译安装。包内还包含 Make.bat、ASPX 与 Global.asax 文件说明提供面向 Web 与桌面环境的示例入口文件类型分布清晰可定位到对应功能模块。目前已有 115 人学习下载作为 MySQL 数据访问方向的可直接参考源码读者可借此掌握 MyDAC 组件内部实现、连接协议封装、数据集处理与跨平台编译技巧并迁移到自身项目中。1. MyDAC v5.00.1.7 源码包到底能干什么一个老 Delphi 组件为什么还在被翻出来MyDAC v5.00.1.7 是 Devart 在 2008 年左右发布的 MySQL 数据访问组件源码包压缩包命名里能看到 MYSQL、MyDAC、MySql.Data src 和 The Client 这几个关键词。它解决的是 Delphi 老项目在不装 MySQL 官方客户端库libmysql.dll的情况下连 MySQL 的问题因为组件源码里自己实现了 MySQL 的 TCP 协议、握手认证、命令封装和结果集解析。源码版比二进制安装版多一层价值你能拆开 MySql.Data 那层协议代码看握手包长什么样能直接改字符集默认值还能把过时的认证逻辑打补丁。适合三类人被老 Delphi 项目绑定、需要在离线环境重新编译交付包的工程师想拿真实组件研究 MySQL 客户端协议的开发者以及接手历史包袱后想留后悔药的人。这篇笔记按拆包、安装、参数、改源码、避坑、验证六步讲。2. 拆开 mydac.v5.00.1.7.src.rar目录结构、Delphi 版本匹配和最小安装路径拿到.src.rar包第一反应都是双击看内容但很多人栽在第一步用错解压工具或者把解压后的整个目录直接塞进 IDE 的 Library Path结果编译报一堆找不到文件的错。先花两分钟把包结构摸清楚后面能省几个小时。2.1 源码目录里都有什么先分清 Source、Packages、Demo 再动手v5.00.1.7 这个版本号里的 5 代表 MyDAC 主版本00 是小版本1.7 是维护号。这种老源码包解压后典型布局是三个目录加一个文档目录。目录典型内容作用Source以 .pas 结尾的 Delphi 单元协议栈和组件实现标题里的 MySql.Data src 就在这里Packages按 Delphi 版本组织的 .dpk 工程编译出 .bpl 和 .dcp供 IDE 安装使用Demo示例工程和脚本拿来模仿连接串和 SQL 用法最直接Documentation官方帮助文件查组件属性虽然老但基本准确核心单元里MyAccess.pas暴露TMyConnection、TMyQuery这些可视化组件DBAccess.pas是 Devart 的统一连接抽象层MySql.Data相关单元负责最底层的协议包收发。标题里的 “The Client” 对应连接握手与会话管理那一块。新手最容易犯的错是打开一个 Demo 工程直接编译然后被 “Unit not found: DBAccess.pas” 砸脸原因不是源码少文件而是搜索路径没指到 Source 目录。解压这一步的额外提醒优先用 7-Zip 而非旧版 WinRAR避免长路径解压被截断。解压后检查一下 Source 目录里MyAccess.pas是否在如果不在就把整个 rar 重新解一次不要手动换目录。2.2 按 Delphi 版本挑 .dpk编译顺序和 IDE 安装步骤MyDAC 5 系列的包工程集中在 Packages 目录里命名习惯是 d5、d6、d7、d9分别对应 Delphi 5、Delphi 6、Delphi 7、Delphi 2009。先确认你手头的 RAD Studio / Delphi 版本再进对应子目录不要凭感觉挑最新的 dpk 双击。包分两组顺序不能反先编译运行时包不带 dcl 前缀再编译设计时包带 dcl 前缀。设计时包引用了运行时包里的类反过来编译会直接失败。步骤如下在 IDE 里打开 Packages 对应版本的MyDAC.dpk。在 Project Manager 里右键工程选 Build确认输出目录生成MyDAC.bpl和MyDAC.dcp。再打开dclMyDAC.dpk右键 Install等待 IDE 状态栏提示组件注册完成。如果编译时提示找不到单元把 Source 目录分别加进 IDE 的 Library Path 和包工程的 Search Path。如果 IDE 的包管理器打开工程时报错另一个可靠手段是走命令行进入 Delphi 安装目录的 bin 下用dcc32.exe编译。命令行能看到完整日志不会被 IDE 吞错误。C:\Delphi2009\bin\dcc32.exe -B -UD:\MyDAC\Source D:\MyDAC\Packages\d9\MyDAC.dpk-B表示全量重新编译-U指定额外单元搜索路径。编译通过后把输出目录加入系统 PATH否则 IDE 加载包时可能报找不到模块。如果你机器上装了多个 Delphi 版本切记不要把输出目录混用否则 .dcu 互相覆盖会让你怀疑人生。2.3 第一个连接用 TMyConnection 在 10 分钟内跑通 MySQL安装完成后再新建一个 VCL 工程拖一个TMyConnection到窗体写一段最小代码验证组件真的能用uses MyAccess; procedure RunMyDACConnect; var Conn: TMyConnection; begin Conn : TMyConnection.Create(nil); try Conn.Server : 127.0.0.1; Conn.Port : 3306; Conn.Username : root; Conn.Password : 123456; Conn.Database : test; Conn.LoginPrompt : False; Conn.Connect; finally Conn.Free; end; end;代码逻辑不复杂但三个细节要当回事LoginPrompt必须显式设为 False否则每次Connect都弹登录框自动化测试会卡死Server建议直接写127.0.0.1不要写localhost老版本组件在 Windows 上会把 localhost 当成特殊分支去走命名管道而 MySQL 默认没开命名管道超时很恼火Conn.Free别漏这个组件体系里连接对象泄漏会一直占着 MySQL 的连接配额时间一长max_connections就被打满。连接参数影响最大的是下面这几个调参时优先看它们参数默认值说明Server空MySQL 主机地址写 IP 最稳Port3306MySQL 默认端口Username空登录账号Password空登录密码Database空连接后默认库LoginPromptTrue建议设 FalseCharsetlatin1老组件默认 latin1中文乱码多发原因ConnectTimeout10 秒左右内网建议设 3 秒故障感知快如果你连 MySQL 服务端都还没装好先去官网下个 MySQL 8.0 的安装包装完再来测。MySQL 8 装完记得确认 root 账号能通过127.0.0.1TCP 访问很多本地安装默认只开了 localhost socketDelphi 这边会连不上。跑通这个最小连接后再往上叠查询、事务和脚本执行。3. MySql.Data 与 Client 单元直连协议的工作原理和关键参数MySql.Data不是微软那个同名库在 MyDAC 源码里它指 MySQL 协议数据层的实现单元。能不能用好这套组件取决于你理不理解它“直连”是怎么回事以及哪些参数是网络层必须对齐的。3.1 为什么 MyDAC 敢不用 libmysql.dll协议栈拆解MyDAC 的核心卖点全在标题里MySql.Data src 和 The Client。它不依赖 MySQL 官方客户端库而是自己在源码里实现了 MySQL 客户端协议。协议从流程上看分成四个阶段TCP 三次握手、服务端发送握手包、客户端回认证包、进入命令循环。MySql.Data相关单元负责的就是第二和第三阶段以及命令循环里对COM_QUERY、COM_PING、COM_INIT_DB这些命令的编码与解包。和 ODBC、ADO 相比直连协议的好处是部署时少一个依赖项。客户机器上不用装 mysql-connector也不用分发libmysql.dll只要把 MyDAC 运行时包打进去就能跑。坏处是协议升级得自己跟MySQL 4.1 之前的旧密码哈希、MySQL 8 的caching_sha2_password都得在源码层追。这也是很多人拿到 v5.00.1.7 源码包的原因自己补补丁比整套换组件更可控。用抓包软件看这段协议会非常直观服务端握手包前四字节是包长度后面跟着协议版本号和服务器版本字符串再往后就是认证插件名。MyDAC 5 解析这段的逻辑没问题但后面遇到不认识的新插件名会直接放弃连接这就是旧组件连不上 MySQL 8 的根本原因不是网络问题。3.2 TMyConnection 的 ConnectionString 与参数含义除了逐属性赋值TMyConnection也支持一整条连接串。这个写法在配置文件里更实用不用改代码就能调整服务器地址。Conn.ConnectionString : Server127.0.0.1;Port3306;User IDroot;Password123456; DataBasetest;Charsetutf8mb4;CompressFalse;Connect Timeout3;连接串里字段名大小写不敏感DataBase和Database都认。重点看Charsetutf8mb4老组件默认 latin1不显式写 utf8mb4 时中文 SELECT 出来大概率是问号。CompressFalse在局域网里能省 CPU因为压缩算法在高速网络里收益很低。Connect Timeout3是超时秒数但老版本里这个参数有时不生效原因是组件在 Windows 上用阻塞 socket 实现连接超时依赖系统 TCP 层。如果你设了 3 秒却挂了 20 秒才报错别怀疑参数没写对这是组件当年的设计限制。一个常见的误用是把密码直接写在连接串里提交到 Git这个习惯比组件本身隐患更大。更合理的做法是从环境变量或配置文件读连接串至少把密码字段拆开。还有个容易被忽略的字段是PoolingMyDAC 5 的连接池默认行为比较朴素设计时给多个窗体共享同一个TMyConnection比开多个连接更省资源。3.3 TMyQuery 执行 SQL 的最小示例和第二参数组连接建好后查询用TMyQuery最顺手。给出最小示例var Q: TMyQuery; begin Q : TMyQuery.Create(nil); try Q.Connection : Conn; Q.SQL.Text : SELECT id, name FROM users WHERE id :minId ORDER BY id; Q.ParamByName(minId).AsInteger : 100; Q.Open; while not Q.Eof do begin OutputDebugString(PChar(Q.FieldByName(name).AsString)); Q.Next; end; finally Q.Free; end; end;这段代码里有三个点值得细看。第一参数用冒号开头ParamByName(minId).AsInteger是命名参数赋值框架会转成 prepared statement 的占位符能有效避免字符串拼接注入。第二Open用于 SELECTExecSQL用于 INSERT、UPDATE、DELETE用错会报错或者返回空结果集。第三结果集遍历完要Free虽然TMyQuery继承自 Devart 组件体系不释放会持续占用 MySQL 连接上的游标资源。参数组还可以按索引访问Q.Params[0].AsString跟ParamByName效果一样但代码评审时可读性差。另外 MyDAC 支持宏参数用macroName表示它不是给用户输入用的而是用来拼 SQL 片段。把外部输入往宏参数里塞是安全灾难记住宏参数只放你写死的片段。3.4 TMyScript 与事务控制批量执行的正确姿势一次要执行多条 SQL 时TMyQuery一条条跑太慢MyDAC 提供了TMyScript组件。把整段 SQL 脚本赋给TMyScript.SQL.Text组件自己按分号拆分、按顺序发送比逐条走ExecSQL快得多。建表、初始化数据、跑存储过程这类场景优先用它。事务控制放在连接对象上写法很直白Conn.StartTransaction; try // 这里执行多条 DML Conn.Commit; except Conn.Rollback; raise; end;MyDAC 5 的事务隔离级别默认是 REPEATABLE READ和 MySQL InnoDB 默认一致。批量插入场景建议每 1000 条提交一次别把几万条全包在一个事务里否则 undo log 膨胀会把磁盘写满。这里还有个常见误区TMyQuery自己也带事务方法但强烈建议统一用连接上的StartTransaction不然嵌套事务的语义在 MySQL 里会变得很微妙。4. 源码级定制改 MySql.Data 的三处常见需求和编译验证源码包的价值就在 “src” 这两个字母上。真正动手改源码的需求通常集中在三块认证协议、字符集、编译验证。改之前先把 Source 目录备份一份带日期地命名这是所有后续折腾的后悔药。4.1 为旧协议打补丁认证握手与 caching_sha2_passwordMySQL 8 默认认证插件是caching_sha2_password握手包里的auth_plugin_name字段会填这个字符串。MyDAC 5.00.1.7 的内部代码只认两种老插件mysql_native_password和mysql_old_password。不认识的插件名会让客户端直接放弃报错Client does not support authentication protocol。补丁思路分三步。第一步在 Source 目录里搜mysql_native_password定位到认证分发逻辑一般是一段 case 分支。第二步在这个分支里增加对caching_sha2_password的处理客户端先发一个空密码响应等服务端返回公钥请求包再用 RSA 加密密码回传。第三步需要在连接属性里打开“获取服务器公钥”的开关类似 JDBC 的allowPublicKeyRetrievaltrue否则服务端不给你公钥认证流程卡死在半路。这里给出一个概念性片段只表示改动位置不是完整实现// MySql.Data 单元内的认证分支示意 case AuthPlugin of mysql_native_password: NativeAuth; caching_sha2_password: begin SendEmptyPassword; if RecvPublicKey then SendRSACryptedPassword(Password); end; end;实际改的时候要顺着源码里的包收发函数找到握手响应包的构造位置auth_plugin_name是握手包末尾的字符串字段从包体尾部解析最稳妥。这个过程会牵扯到 RSA 加密函数老代码里可能没有现成的实现需要把它引到 Delphi 的加密库或自己写。改完先别急着上生产验证方法还在第 6 章。4.2 字符集与排序规则源码里哪个常量决定 utf8mb4老组件的默认字符集常量通常定义在MySql.Data的初始化代码里。MySQL 用数字 ID 表示字符集utf8是 33utf8mb4是 45latin1是 8。MyDAC 5 默认握手时把客户端字符集设成 33这在 MySQL 5.5 之前够用因为 utf8 还能存基础中文遇到 emoji 或冷门生僻字就变成乱码或者直接报错。查找方法很直接在 Source 目录全文搜索Charset或者33找到类似FCharsetID的字段初始化位置把默认值改成 45。但这里有个优先级问题组件属性Charset和源码默认值冲突时以显式赋值为准。所以最稳的做法是在代码里显式写Conn.Charset : utf8mb4源码默认值只作为没设置时的兜底。改完源码后可以用这条 SQL 验证客户端字符集真的变了SHOW VARIABLES LIKE character_set_client;如果返回utf8mb4说明握手包里的字符集 ID 已经生效。如果返回还是latin1优先检查是否显式赋了Charset属性因为它会覆盖源码补丁。4.3 编译自定义版本如何绕过 .dcu 残留和路径污染改完 .pas 文件编译时最经典的坑是改了源码行为没变。第一反应是没重编第二反应是编译了但链接到了旧 .dcu。Delphi 的编译器非常依赖缓存判断文件时间戳一变就全量重编但如果机器上有多个 MyDAC 副本搜索路径会优先命中旧目录。解决办法是用命令行全量重编不经过 IDE 的增量逻辑C:\Delphi2009\bin\dcc32.exe -B -Q -UD:\MyDAC\Source D:\MyDAC\Packages\d9\MyDAC.dpk-B全量重建-Q安静模式只输出错误-U指定单元搜索路径。命令跑完会生成新的 .bpl 和 .dcp。接着把 IDE 里的运行时包卸载再装回去否则 IDE 进程还锁着旧 .bpl等于白编译。路径污染的典型表现是 Source 目录和 Packages 目录里都有同名 .pas编译时取了旧的那份。解决方法是先把源码目录下的 .dcu 全删掉可以用 Everything 按扩展名搜出来批量删再在包工程 Options 里把 Search Path 改成 Source 目录的绝对路径避免相对路径在不同 IDE 版本下解析不一致。删除 .dcu 是个清理动作不是搞破坏Delphi 下次编译会自动重新生成比重装整个 IDE 高效得多。4.4 确认改动真的进包断点与调试输出的土办法编译安装完最怕遇到“改了没反应”的玄学。一个非常有效的核实方法是在改动后的源码行上打一个断点然后运行一个用TMyConnection连库的 Demo。如果断点变灰色或者提示模块未加载说明 IDE 链接的不是你刚编的 .bpl回到 4.3 重新检查搜索路径和包安装状态如果断点正常命中说明改动确实进了运行时包。另一个快速技巧是在改动的位置临时加一句OutputDebugString编译后用 DebugView 捕获输出。这个方法比设断点更快不需要关心 IDE 是否弹断点窗口只要跑一遍连接过程就能看到日志。确认无误后记得把调试输出删掉免得交付包里带上调试噪音。源码级定制的全部流程走完你的 MyDAC 已经跟别人手上的安装版不是一个东西了。5. 避坑老源码包在 Windows 上编译安装的 5 个典型事故MyDAC v5.00.1.7 源码包价值高但毕竟年代久Windows、Delphi、MySQL 三方版本错配会让整个过程变成玄学。下面五条是实际项目里最容易踩的按现象、原因、解决分别写清楚。5.1 现象编译报找不到 MyAccess.pas 或 DBAccess.pas打开示例工程或自己新建工程编译时第一行直接报Unit not found: MyAccess.pas。这本是最容易修的错但新手经常修到暴躁。原因Source 目录没进 IDE 的 Library Path或者包工程的 Search Path 里只写了 Packages 目录。另外解压工具截断长路径也会导致MyAccess.pas物理缺失。解决先用 Everything 搜MyAccess.pas确认文件真实存在的位置然后在 IDE 的Tools Options Environment Options Library Path里加入 Source 目录最后在包工程的Project Options Directories/Conditionals Search path里也加一遍。两条路径都改IDE 缓存才不会捣乱。5.2 现象dcl 包安装提示无法加载指定的模块运行时包 Build 成功安装设计时包dclMyDAC.dpk时报Cannot load package ... module not found。原因设计时包引用的 .bpl 不在 Windows DLL 搜索路径里。Delphi IDE 加载包遵循系统搜索规则先查包所在目录再查系统 PATH。输出目录没进 PATH 就找不到。解决把.bpl输出目录加入系统 PATH或者直接把编译生成的.bpl复制到 Delphi 的 bin 目录。改完 PATH 要重启 IDE 生效别问为什么没反应重启一下就好。5.3 现象连接 MySQL 8 报 Client does not support authentication protocol这是老组件连新数据库时最典型的报错。MySQL 5.7 之前默认认证插件是mysql_native_passwordMySQL 8 开始默认caching_sha2_passwordMyDAC 5.00.1.7 的握手代码不认这个新插件直接拒绝认证。原因组件握手代码里的认证插件分支太老具体机制在第 4.1 节已经拆过。如果不想改源码还有一个临时方案把 MySQL 用户改回旧认证插件。ALTER USER root127.0.0.1 IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;这个办法适合开发环境快速跑通生产环境不建议用因为 MySQL 8 官方已经在推动弃用mysql_native_password。生产环境要么给 MyDAC 打源码补丁要么直接升级组件到一个支持新认证的新版本别为省事埋雷。5.4 现象查询中文全是问号或乱码连接正常SELECT 出来的中文显示成??或半个字UPDATE 进去的中文再读出来是乱码。这是字符集没对齐的典型表现。原因MyDAC 5 默认Charset是 latin1而服务端和表的 collation 是 utf8mb4。客户端字符集 ID 会在握手包发给服务端服务端按这个 ID 做字符转换两边不一致就出乱码。解决在 ConnectionString 里显式加Charsetutf8mb4同时确认数据表和字段的 collation 是utf8mb4_general_ci或utf8mb4_unicode_ci。改完重连再用SHOW VARIABLES LIKE character_set_client确认值已经变成utf8mb4。如果还乱码检查服务端my.cnf里的character-set-serverutf8mb4是否写了对。5.5 现象连接 localhost 超时127.0.0.1 却秒连这个坑非常隐蔽。Server : localhost挂起十几秒后报超时改成Server : 127.0.0.1瞬间连上。很多人怀疑是 MySQL 配置问题其实不是。原因MyDAC 5 在 Windows 上把localhost识别成本机特殊分支尝试走命名管道或 socket 文件而 MySQL for Windows 默认关闭named_pipe。组件在解析主机名时先走了特殊分支绕不过去。解决Server一律写127.0.0.1不要写localhost。如果确实想用命名管道连接本机需要在 MySQL 配置文件里显式开启named-pipeON但日常开发完全没必要直接走 TCP 更稳定。提示第 5.3 和 5.5 的坑经常叠加出现。先确保Server是127.0.0.1再处理认证插件否则你可能会在超时和认证错误之间反复横跳误判问题范围。6. 验证改装版 MyDAC压测、抓包和回归测试的土办法改完源码、装好包、能连上还不能直接上生产。我用三个土办法验证成本低效果实在。第一最小回归。写一个控制台程序循环执行 1000 次SELECT 1记录总耗时。协议层的改动不该影响正确性如果中途挂掉多半是缓存或错误处理问题。命令行批量跑一遍for /l %i in (1,1,1000) do mydac_test.exe -c SELECT 1第二抓包验证。Wireshark 抓 3306 端口筛选tcp.port3306。重点看第二个 TCP 包里的auth_plugin_name字段确认服务端返回的是不是caching_sha2_password再看客户端回的认证包确认密码已经是加密态。这个验证能直接确认你的补丁走的是预期分支比看代码更可靠。第三和 Workbench 对拍。用 MySQL Workbench 跑同一批 SQL对比结果集行数和排序。Workbench 代表最新客户端协议两边结果一致说明 MyDAC 解析结果集的逻辑没被改坏。这个方法尤其适合验证字符集改动Workbench 显示正常但 MyDAC 乱码时问题基本锁定在握手包的字符集 ID。最后说个习惯我每次改完组件源码原始 .pas 都会备份一份命名带日期。第一次改caching_sha2_password时我把公钥抓取逻辑写反了连备份库都进不去还好Server一直是127.0.0.1最后靠 Wireshark 抓包确认是认证包被拒。那之后我记住了抓包是黑匣子的后悔药备份是手贱的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表