
简介MyDAC v5.10是一套定位明确的MySQL数据访问组件源码面向长期使用Delphi或CBuilder的桌面应用开发者用于在不依赖中间件的情况下直连MySQL服务器实现增删改查、事务处理、批量提交、存储过程与异步调用等常见数据库需求并兼顾高性能和低资源占用。资源包整体仅约1.39MB共包含1403个文件文件类型以pas源文件、dpk与dproj工程文件、dfm窗体、res资源、bdsproj项目配置、bmp图标以及html帮助文档为主覆盖源码、界面、工程与文档多个维度结构清晰适合按目录检索和二次编译。已有166人学习下载。使用者可以获得完整组件源码还有历史更新记录、FAQ、许可协议和源码编译指引等配套说明既能快速了解组件能力与接口用法也能根据自身业务对数据库访问逻辑做定制化调整适合需要在旧版Delphi和CBuilder环境中稳定接入MySQL的中高级开发者。1. MyDAC v5.10 源文件免装 MySQL 客户端库的 Delphi 连接层组件源码做 Delphi 开发的人几乎都囤过一份 MySQL Data Access Components (MyDAC) v5.10 源文件。它不是装好的交付包而是把 TMyConnection、TMyQuery、TMyScript 的整套源码摊开给你看。MyDAC 最大的价值在 Direct 模式组件自己实现了 MySQL 网络协议客户机不用装 libmysql.dll部署时少带一个库。适合两类人一类在维护 Delphi MySQL 老系统想把数据库连接层这个黑匣子换成自己能改的源码另一类是研究 Delphi 组件库怎么实现 TCP 协议和结果集解析的。下面按我实际拆包的顺序讲目录、安装、连接参数和几个踩过才知道的坑。2. 拆包与选型源码包里哪组包文件对应你的 Delphi 版本2.1 目录结构Source、Demos、Help 各负责什么解压后先别急着双击.dpk先把根目录看明白。MyDAC v5.10 这种源码包目录一般是三块Source、Demos、Help。Source里是核心单元所有组件的.pas、.dpk、.inc都在这里这是唯一需要参与编译的部分。有些版本的Source下还有按 Delphi 版本拆分的子目录比如Delphi7、Delphi2009这些子目录里往往只放包工程文件公共代码仍在Source根目录你编译时要用哪个子目录取决于你手上的 IDE 版本。Demos是官方示例工程从简单查询到存储过程调用都有适合在组件装完之后验证环境。但第一次打开工程不建议从 Demos 开始因为示例工程引用的包名和路径通常和你当前 IDE 的配置不一致直接打开会弹出一堆找不到单元的错误反而干扰对源码包的判断。Help是编译好的.chm里面能搜到TMyConnection每个属性的说明很多老版本帮助文档还带源码内嵌的注释查询字段含义比翻网页快。判断这套资源是不是“完整源文件”我一般只看两点Source目录下有没有.dpk以及有没有.inc编译条件文件。.dpk是 Delphi 包工程负责把.pas组织成可安装组件.inc里定义了哪些单元参与编译、哪些特性按版本开关。如果只有.pas没有.dpk那它只是运行时单元集合装进 IDE 组件面板需要自己手工建包工程麻烦得多。MyDAC v5.10 这套是两者齐全的标准包安装路径就是“先编译运行时包、再编译安装设计时包”。2.2 版本边界v5.10 能对上的 MySQL 与 DelphiMyDAC 5.10 的时代大致对应 MySQL 5.x它实现的认证协议、SQL 方言和字符集交互都停留在 5.x 的能力范围里。MySQL 5.0、5.1、5.5、5.6 我都连过稳定工作5.7 也碰过没有异常。但 MySQL 8.0 默认的caching_sha2_password认证插件在这版源码的协议握手代码里没有实现直接用会翻车具体处理方式放到 5.2 节讲。Delphi 侧要看 dpk 文件名的后缀。Devart 的包文件命名习惯是带版本号的比如MyDAC160.dpk对应用 Delphi 16也就是 XE10dclMyDAC160.dpk是它对应的设计时包。拿到包以后先在Source目录里找有没有跟你 IDE 版本号一致的 dpk 文件名找不到也不要立刻换版本很多老包在新 IDE 里只是需要重编一次。需要注意的是新版 Delphi 对 dcu 有严格的版本校验老包用旧 IDE 编出的 dcu 拿到新版 IDE 里直接报F2051这不是源码坏是编译环境不匹配删掉旧 dcu 重新编即可。2.3 运行时包与设计时包dcl 前缀决定安装顺序一个 Delphi 组件包分两种角色这个不弄清楚后面装了一定乱。运行时包MyDAC*.dpk提供的是编译期单元和运行期宿主的底层代码你写代码时uses MyConnection用的就是它。设计时包dclMyDAC*.dpk是给 IDE 集成使用的它把组件注册到窗体面板上让你能在设计期拖动组件到 Form。设计时包含有对 IDE 开放接口的引用因此它的编译依赖运行时包。我见过有人只装了 dcl 包不装运行时包结果打开 dcl 工程提示找不到MyConnection单元也有人反过来运行时包装好但设计时包没装代码里能uses但组件面板上找不到图标。正确顺序是先编译运行时包等它生成.dcu和.bpl之后再编译并安装设计时包。如果你只做命令行编译、不打算在 IDE 上拖组件那就跳过 dcl 包运行时包足够。装完以后组件面板里会出现一个 MyDAC 分类里面的TMyConnection、TMyQuery就是后面要用的对象。3. 安装进 IDE从 Library Path 到设计时包的三段编译流程3.1 阶段一把 Source 目录写进 IDE 的 Library PathLibrary Path 是 IDE 按顺序搜索编译单元的位置列表。默认情况下它包含$(DELPHI)\Lib等路径IDE 编译工程时工程自身搜索路径里找不到的.pas单元就会来库路径里碰运气。把 MyDAC 的Source目录加进去是为了让后续编译 dpk 时能找到MyConnection.pas这类地基单元缺失时编译会直接报F1026 File not found。具体操作分三步。第一步打开 IDE 的Tools → Options → Delphi Options → Library第二步在Library Path输入框末尾追加解压目录\Source多路径之间用分号隔开第三步点击Update保存。新版 Delphi 会把 32 位和 64 位的 Library Path 分开配置如果后续要交叉编译两个条目都要加一遍。注意不要加错到Browsing Path那是给代码提示用的不参与编译单元搜索加错了编译照样找不到。提示如果Source下有按版本拆分的子目录Library Path 里就把子目录路径排在最前面公共代码目录排后面。编译器按路径先后顺序找.pas匹配到的第一份会生效。3.2 阶段二运行时包与设计时包的编译顺序运行时包和设计时包的编译顺序错了轻则报缺单元重则 IDE 组件面板被污染。先把Source目录下对应你 IDE 版本的MyDAC*.dpk打开在 Project Manager 中右键选择Compile等待状态栏出现Compile Successful。然后打开dclMyDAC*.dpk同样先Compile再右键选Install。Install 完成会弹窗提示组件已注册到工具面板这才是装完。如果 Compile 时报F2051或E2225说明 dcu 版本和当前 IDE 不一致回到 2.2 的处理办法删掉Source下所有.dcu、.bpl然后重新编译运行时包。另外有些老版本包还会读.inc里的版本判断如果包文件带IF条件编译编译日志里会看到具体是哪一项被跳过了这种不是致命错误只是关闭了某些新功能。安装完成的标志性验证新建一个 VCL 工程打开 Form 后看组件面板如果 MyDAC 分类在且能拖出TMyConnection环境就算打通了。不要急着写业务代码先拖一个空组件到 Form 上编译一次空工程确认没有缺少运行时包。这一步能过滤掉后续 70% 的“编译通过但运行报错”问题。3.3 阶段三工程引用与部署时的 bpl 和 dcu 选择组件装好以后使用方式分两种部署取舍完全不同。第一种是动态链接运行时包在工程Options → Packages里勾选对应 MyDAC 包exe 编译出来后体积小但发布时必须把MyDAC*.bpl和它依赖的 Delphi RTL bpl 一起带到目标机器。第二种是静态链接把包文件从 Runtime Packages 里移除单元直接编进 exe体积增加但发布时只带一个 exe。我自己的习惯是对内部工具这种目标环境可控的程序用静态链接省得丢包对要分发到客户现场的正式系统优先动态链接因为后续打补丁的时候只换 bpl 文件就能更新组件层不需要重新编译整个 exe。部署到纯净 Windows 环境还有一个注意点如果TMyConnection.Options.Direct设成了 False那么组件会走官方客户端库libmysql.dll这个 dll 必须跟着 exe 走而且位数要和 exe 一致32 位 exe 配 64 位 dll 会静默加载失败连接时报“无法定位程序输入点”。DirectTrue 则完全绕过这个问题这也是我推 Direct 模式的原因。4. 编码上手TMyConnection 连接参数、参数化查询与事务的代码落地4.1 属性配置Server、Port、Direct 与 Options.Charset 的选型TMyConnection 的连接参数核心就下面这几个属性面板和代码里字段是同一套属性典型值说明Server127.0.0.1主机名或 IP建议写 IPPort3306MySQL 服务端 TCP 端口Usernamemyapp业务专用账号不建议用 rootPassword从配置读取不要硬编码到源码Databasemydb默认 SchemaOptions.DirectTrue直连协议绕过 libmysql.dllOptions.Charsetutf8mb4与库表排序规则保持一致Server 字段我几乎不写localhost。Direct 模式是通过 TCP 协议直连服务端localhost在部分 Windows 环境会被解析成命名管道或者 unix socket服务端不开管道时直接连接失败写127.0.0.1最稳。Port 默认 3306如果现场改过端口代码里必须显式指定否则默认端口连上以后看着像“服务未启动”其实是端口不对。Options.Direct 是这组件最值得用的特性。True 时 MyDAC 自己完成 MySQL 握手和命令解析不依赖官方客户端库False 时它退化为客户端库封装此时部署必须带 libmysql.dll。老项目我一般固定 True环境干净很多。Charset 值要和数据库实际字符集对齐MySQL 5.5 之后普遍用utf8mb4老库如果是latin1连接时先别强制改否则读取可能乱码具体在 5.3 展开。4.2 TMyQuery 参数化查询一段可直接落地的查询模板下面这段是我最常用的查询写法包含连接赋值、参数绑定、遍历结果三件事。参数绑定是 MyDAC 的一个优势点它会在客户端把参数值转成正确的类型再发往服务端比你手工拼字符串安全得多。procedure QueryUsersByDept(AConn: TMyConnection; const ADept: string); var Q: TMyQuery; begin Q : TMyQuery.Create(nil); try Q.Connection : AConn; Q.SQL.Text : SELECT id, nickname, created_at FROM users WHERE dept :dept ORDER BY id DESC; // MyDAC 的命名参数用冒号开头ParamByName 按名称取对象 Q.ParamByName(dept).AsString : ADept; Q.Open; // Open 用于 SELECT返回可遍历的结果集 while not Q.Eof do begin // 处理当前行数据 LogMessage(Q.FieldByName(nickname).AsString); Q.Next; // 游标后移 end; finally Q.Free; // 查询对象记得释放否则长循环里会累积句柄 end; end;逻辑上分四步创建 TMyQuery、绑定 TMyConnection、设置 SQL 和参数、Open 后遍历。Q.Open对应 SELECT会获取结果集如果执行 UPDATE/INSERT/DELETE要换用ExecSQL原型是ExecSQL(const SQL: string)或者带上参数数组的重载版本。ParamByName(dept).AsString : ADept这行是核心参数类型跟随赋值的类型走服务端收到的是字符串而不是拼接的 SQL能有效防注入。迭代结果集时FieldByName(nickname).AsString每次取字段值字段名写错会运行时报EDatabaseError最好的规避方式是先把 SELECT 字段列表和后面取值的名字对一遍。游标Q.Next别忘了写漏掉就是死循环。最后Q.Free释放对象组件被反复创建的循环场景下尤其重要Delphi 的泄漏检测打开以后能看到这类问题。4.3 事务边界与 TMyScript 批量执行老手写事务最怕的不是 SQL 错而是想着事务却不知道怎么定义边界。MyDAC 的事务控制在 TMyConnection 里StartTransaction 开启Commit 提交Rollback 回滚。下面是一个典型的账户扣减和增加场景两个 UPDATE 必须在同一事务里否则中间断电会出现钱少了但对方没收到的情况。procedure TransferBalance(AConn: TMyConnection; AFromId, AToId: Integer; AAmount: Currency); begin AConn.StartTransaction; try // ExecSQL 执行 UPDATE参数数组按 :amt/:id 顺序传入 AConn.ExecSQL( UPDATE accounts SET balance balance - :amt WHERE id :id, [AAmount, AFromId] ); AConn.ExecSQL( UPDATE accounts SET balance balance :amt WHERE id :id, [AAmount, AToId] ); AConn.Commit; except AConn.Rollback; raise; // 回滚后继续向上抛异常交给上层统一处理 end; end;ExecSQL 的重载版本第二个参数是array of const[:amt, :id]这种写法要求占位符出现顺序和数组顺序一致参数名本身不重要顺序必须对。StartTransaction 之后的异常块里一定要 Rollback否则事务停留在未决状态后续连接复用时会报“Commands out of sync”。TMyScript 组件要单独说一下它是给一个脚本文件或字符串执行多条 SQL 用的比如初始化建表、数据迁移。TMyQuery 只能一次执行一条语句把多条 SQL 塞进 TMyQuery 的 SQL.Text 里只会执行第一条剩下全部被忽略。TMyScript 会按分号分割语句逐条发送适合跑建表脚本。procedure RunInitScript(AConn: TMyConnection; const AScript: string); var MyScript: TMyScript; begin MyScript : TMyScript.Create(nil); try MyScript.Connection : AConn; MyScript.SQL.Text : AScript; MyScript.Execute; finally MyScript.Free; end; end;业务里如果需要调用 MySQL 存储过程MyDAC 提供了 TMyStoredProc设置StoredProcName : sp_reduce_inventory然后ExecProc输入输出参数用ParamByName访问即可。存储过程返回结果集时ExecProc 之后遍历方式与 TMyQuery 一致只是 Open 不能调用改用Execute再取数据。5. 避坑记录MyDAC v5.10 安装与连接时五个高频报错的排查方法5.1 编译报 F2051单元版本不一致现象编译dclMyDAC*.dpk时IDE 报F2051 Unit MyConnection was compiled with a different version of System.Types后面经常跟一串编译版本号。这属于 Fatal Error整个安装流程直接中断。原因Source 目录里残留了其他 IDE 版本生成的.dcu文件。Delphi 对 dcu 头信息里有严格的编译器和 RTL 版本校验本机 IDE 的System.Types版本与旧 dcu 不匹配时直接拒绝链接。另外一个常见诱因是 64 位/32 位平台的 dcu 混放在同一个目录。解决全盘搜索Source目录下所有.dcu和.bpl删除干净保留.pas、.dpk、.inc不动然后重新编译运行时包。如果删完仍报错检查Tools → Options → Library里的BPL Search Path确认没有指向其他版本 MyDAC 安装目录的路径。这一步做完F2051 九成以上能消除。5.2 连接 MySQL 8 报 Authentication plugin 错误现象程序连接 MySQL 8.0.x 时报Authentication plugin caching_sha2_password cannot be loaded或Unknown authentication plugin连接被服务端拒绝但用命令行却能连上。原因MySQL 8 默认创建用户时认证插件是caching_sha2_passwordMyDAC v5.10 的握手协议实现不包含这个插件它在服务端校验阶段就把客户端判定为不兼容。这属于协议层不支持单改客户端参数解决不了。解决在 MySQL 服务端把该用户切换回mysql_native_password这是 MyDAC v5.10 能正常识别的认证方式。执行下面的 SQL 后重新连接ALTER USER myapp% IDENTIFIED WITH mysql_native_password BY password; FLUSH PRIVILEGES;注意%要换成实际的 host 范围FLUSH PRIVILEGES只刷新权限缓存对已存在的连接不生效需要重连。如果你是新接触 MySQL 8 又有选择余地更彻底的方案是升级到支持新版认证的 MyDAC 版本但老项目里往往不便动组件改用户认证插件是最快的后悔药。5.3 中文乱码连接字符集与库表 collation 不匹配现象查询结果里中文字符显示为问号写入后字段内容变成乱码。明明表结构已经设置了DEFAULT CHARSETutf8仍然乱。这算是 MyDAC 旧版本现场最出名的血泪经验。原因表字符集只决定数据存储格式连接字符集决定服务端与客户端之间传输的编码。MyDAC 的Options.Charset如果没设置默认可能按latin1处理交互服务端把 utf8 字段返回后按 latin1 解析必然乱码。解决三个位置要拉齐。第一数据库表结构确认是 utf8mb4第二连接组件设置Options.Charset : utf8mb4第三考虑到老 MySQL 5.0/5.1 对 utf8mb4 支持不完整可以在连接建立后强制执行一次SET NAMES确保会话级字符集不被服务端全局变量覆盖。procedure TDataModuleMy.MyConnectionAfterConnect(Sender: TObject); begin TMyConnection(Sender).ExecSQL(SET NAMES utf8mb4 COLLATE utf8mb4_general_ci); end;字符集问题排查时要按链路逐步隔离先用命令行客户端查询同一张表确认数据本身不是乱码再测组件直连不带SET NAMES最后加上Options.Charset对比。MySQL 5.7 以下如果遇到表情符号写入异常多半是 utf8 不够用必须走 utf8mb4。5.4 Direct 模式连 localhost 失败但连 127.0.0.1 正常现象Server : localhost时连接报Cant connect to MySQL server on localhost (10061)改成Server : 127.0.0.1后立刻正常。原因Direct 模式是纯 TCP 连接localhost在部分系统上会被解析为 IPv6 的::1而 MySQL 服务端配置可能只监听了 IPv4 的 3306导致连接被拒绝。还有一种情况是 Windows 把 localhost 解析成本机命名管道Direct 模式不处理管道协议于是报错。解决统一把 Server 写成127.0.0.1这是最干净的方案。如果现场必须写主机名检查 MySQL 的bind-address配置确认服务端监听地址包含对应 IP。服务端如果开启了skip-networkingTCP 端口会完全关闭Direct 模式必然连不上需要把该参数设为 0 并重启 MySQL才能接受网络连接。5.5 连接池开启后服务端连接数被打满现象程序运行一段时间后 MySQL 的SHOW PROCESSLIST里出现大量Sleep状态的连接超过max_connections新增业务全部报Too many connections。原因MyDAC 的连接池在Options.Pooling : True时会保持多个物理连接复用进程退出前如果没有显式断开连接会残留。池里的空闲连接超时行为由服务端wait_timeout控制客户端感知不到服务端已经断掉下一次拿旧连接执行语句时报MySQL server has gone away。解决程序主窗体关闭或服务停止时显式调用MyConnection.Disconnect释放连接池不要只依赖对象析构。池参数也要跟着服务端限制走Options.Pooling保持 False 是最保守的做法打开池时注意Options.MaxPoolSize如果服务端max_connections是 200池上限设在 50 以下更稳妥。清理现场残留连接用SHOW PROCESSLIST; SELECT COUNT(*) FROM information_schema.processlist WHERE Command Sleep;定位到残留连接后执行KILL 连接ID;即可。连接池化解了反复握手开销但池的参数必须和 MySQL 服务端配置联动任何一边单独改都会出问题。6. 进阶验证用连接日志和最小自检把连接稳定性查到根上6.1 打开 OnLog 与 LogFile 观察协议握手细节连接失败时只说“连接失败”不能说明问题。MyDAC 提供了LogFile属性和OnLog事件把协议层交互过程落盘。设置LogFile指向一个文本文件组件会自动把握手、认证、执行语句等环节写入挂上OnLog事件就能把日志同时输出到界面上procedure TDataModuleMy.MyConnectionLog(Sender: TObject; Event: TLogEvent; const Msg: string); begin MemoLog.Lines.Add(Format([%s] %s, [EventToStr(Event), Msg])); end; MyConnection.LogFile : C:\logs\mydac.log; MyConnection.OnLog : MyLog;TLogEvent是 MyDAC 在源码中定义的枚举区分leConnect、leExec、leFetch、leDisconnect、leError等事件。排查连接失败时先看有没有leConnect事件没有说明 TCP 都没通有leConnect但随后leError报认证插件那就是 5.2 的问题。日志能告诉你失败发生在协议的哪一层省得反复猜。6.2 连接池参数Pooling、MaxPoolSize 与等待时间前文 5.5 提过连接池这里补充参数调优的习惯做法。Options.Pooling设为 True 后注意三个值MaxPoolSize控制池内物理连接上限默认 0 表示不限制对服务端不友好的系统要按max_connections的 1/4 来设PoolTimeout控制空闲连接回收时间取值要比服务端wait_timeout小否则客户端复用已被服务端断开的连接会报错。连接池不是越大越好我一般在并发峰值估算的基础上加 20% 余量宁可排队也不让服务端连接数爆掉。6.3 一个我坚持了很多年的自检习惯每次拿到新环境、换 MySQL 服务端或升级 IDE我都不直接跑业务代码而是先编译一个只有 TMyConnection 和 TMyQuery 的最小控制台程序做三件事连接、执行SELECT 1、开启一个事务后回滚。连接成功确认网络和端口通SELECT 1确认协议握手和认证通过事务回滚确认服务端支持事务且没有会话级干扰。三件事全过我再把业务模块引进来。从那以后每次现场出问题我都会先强制走一遍这个最小自检把环境问题和代码问题切分开这习惯帮我省下过大量排查时间。希望帮到你。本文还有配套的精品资源点击获取