MyDAC v5.10源码解析:Delphi连接MySQL的安装、排错与定制

发布时间:2026/10/14 6:45:40
MyDAC v5.10源码解析:Delphi连接MySQL的安装、排错与定制 简介MySQL Data Access ComponentsMyDACv5.10完整源文件包专为Delphi 7至2007与CBuilder开发者设计用于在不依赖第三方库或中间件的情况下直接连接MySQL服务器覆盖事务处理、批处理操作、存储过程、异步机制与错误处理等能力适合需要高效稳定数据库访问或进行组件级二次开发的场景。资源共1403个文件压缩包仅1.39MB包含360个Pas单元源码、146个Dpk工程、107个Dfm窗体、95个Cfg配置及Bdsproj、Bmp、Obj等类型覆盖组件实现、IDE安装工程与界面资源。随包附有Hlp/Cnt帮助索引、History更新记录、FAQ问答、Readme说明、License许可及Make编译脚本便于查阅和重新编译。已有167人学习下载。开发者可借助完整源码理解MyDAC内部机制并按需裁剪或深度定制是旧版IDE环境下MySQL数据库开发与控件研究的实用资料。1. MyDAC v5.10 源文件老 Delphi 项目连 MySQL 绕不开的一堆源码手边出现一套 MySQL Data Access Components (MyDAC) v5.10 源文件大概率是两种处境要么你在接手一个十来年前用 Delphi 写的业务系统原维护者只移交了一个源码压缩包要么你正在评估给老项目换数据库访问层不想继续被 BDE 和 ODBC 折腾。MyDAC 是 Delphi/C Builder 环境下原生直连 MySQL 的数据库访问组件集v5.10 属于那几年里很稳的一代。它解决的问题很具体不需要装任何驱动、不需要中间数据服务IDE 里拖一个连接控件、填上服务器地址和账号就能开始读写 MySQL。这套东西适合维护遗留 ERP、进销存、MIS 系统的工程师也适合所有不想再把连接问题当玄学的人——源文件在手每个环节都能拆开看。下文按安装、连接、读写、排错、定制这条线把整条路走通。2. 看懂源文件包再动手MyDAC v5.10 的目录结构与安装闭环拿到源文件直接双击某个包工程就编译大概率翻车。包内单元有依赖顺序路径配置也不只是把文件夹加进去那么简单。先把源文件的组织方式讲清楚再给一套能落地的安装流程。2.1 核心单元地图连接、命令、元数据、批量导入各管一摊源文件包和安装版最大的差别在于没有绑定具体 IDE 版本的编译产物。你手里是一批 .pas 源码单元、若干 .dpk 包工程和文档。按职责划分MyDAC v5.10 的代码面可以分成四层搞清楚这四层编译报错时能立刻判断缺了哪一块。第一层是连接内核对应 TMyConnection。它负责建立和管理与 MySQL 服务器的会话包括 TCP 握手、身份认证、事务状态维护、连接参数缓存。几乎所有其他组件都依赖一个已连接的 TMyConnection 实例所以这一层没有可替代路径编译时必须最先通过。第二层是读写命令层对应 TMyQuery、TMyTable、TMyCommand。TMyQuery 最常用既能 Open 出结果集也能用 ExecSQL 执行写操作TMyTable 面向单表操作TMyCommand 适合轻量命令。第三层是批量与脚本层TMyScript 一次执行多段 SQLTMyLoader 专做大吞吐数据装载。第四层是元数据与监控TMyMetaData 读表结构TMyMonitor 记录客户端与服务器之间的原始报文。把组件映射回源文件通常能看到这几类文件连接核心单元、协议解析单元、组件封装单元、设计期注册单元。设计期单元只服务于 IDE 可视化安装发布程序时不需要编译进去。我编译时习惯严格按「连接核心 → 命令层 → 设计期包」的顺序推进一旦报错错误信息指向的就是还没满足依赖的那一层不会出现到处乱报的假象。2.2 在 IDE 里安装组件库路径、搜索路径与两个包的先后顺序常见做法是把源文件目录的用途拆成两份一份加进 IDE 的库搜索路径让所有项目都能 uses 到组件单元另一份用于编译包工程生成设计期组件。先配置路径打开 Delphi 的 Tools Options Library老版本在 Environment Options 里把 MyDAC 源码根目录加入 Library Path。注意加入的是根目录而不是某个子目录因为单元文件可能按功能分散在多个子目录漏加会导致编译器搜不到报错信息还会误导你反复改路径。组件安装本身分两步顺序固定。先打开运行时包工程文件一般是 .dpk 或 .dproj名字里通常带 Runtime 字样编译通过后生成运行时 DCU 和 BPL。再打开设计期包工程点 Install 注册到 IDE 组件面板。设计期包依赖运行时包顺序反了会一路报缺单元。如果源文件提供的是新版工程格式也可以用命令行编译# 先用 Release 配置编译运行时包产物用于后续分发包名以实际源文件为准 msbuild MyDACRuntime.dproj /t:Build /p:ConfigRelease # 再用 Debug 配置编译设计期包供 IDE 安装使用 msbuild MyDACDesign.dproj /t:Build /p:ConfigDebug两条命令里msbuild 是较新 IDE 的构建入口老 IDE 没有 msbuild直接用集成环境打开 .dpk 文件先 Compile 后 Install 效果一样。关键在顺序运行时包在前、设计期包在后。包工程的具体名字存在差异以你手里的源文件为准别照着记忆里的文件名硬找。这里有一个容易踩的选项包工程的输出目录。很多源文件包默认输出到 IDE 公共 DCU 目录机器上装过多个版本时新旧 DCU 会混在一起。我习惯把输出目录改到源文件包内的 build 子目录每次重编前先删掉 build 目录保证加载的必然是全新产物排查环境问题会干净很多。注意条件编译指令比如针对不同 IDE 版本的 {$IFDEF}受源文件当时的支持范围限制。跨大版本使用老源码编译不过不一定是你的问题先确认源文件声明支持的 IDE 版本。2.3 重新编译的边界哪些必须自己 build哪些可以直接用源文件里的 .pas 是跨 IDE 版本通用的但编译出的 DCU 不是。Delphi 大版本之间二进制不兼容所以只要你的 IDE 比 v5.10 时代新就必须全部重新编译。反过来说手头正好有那个年代的老 IDE理论上可以直接用包内附带的 DCU我仍然建议重编一遍你无法确认那些 DCU 的编译选项、补丁级别和优化开关留着等于给后续排错埋雷。统一重编花不了多少时间换来的是一个干净基线。有一类文件不需要你编译但运行期必须存在MySQL 客户端库。MyDAC 访问 MySQL 走客户端库协议常见形式是运行时动态加载 libmysql.dll。这个 dll 不是组件源码的一部分要去 MySQL 发行包里拿而且服务器大版本不同dll 也要对应。编译组件时用不到它运行程序时才加载所以它的报错总在程序启动之后而不是编译阶段。这类问题放进第五章集中讲。3. 连接是第一步也是最多坑的源头TMyConnection 参数与连接串数据库组件的故障超过一半发生在连接层。连接参数没配好后面所有 SQL 都无从谈起。这一章把 TMyConnection 的关键参数、两种赋值方式和验证手段一次说透。3.1 必须写对的 5 个基础参数外加一个字符集TMyConnection 的属性方式比连接串直观高频参数就这几个参数典型值说明Server192.168.10.5服务器 IP 或主机名本机可填 localhostPort3306MySQL 默认端口改动过必须显式指定UserNameapp_user连接账号建议按最小权限原则创建Password——对应用户密码Databaseerp_db默认数据库留空则连接后无当前库SQL 要带库名前缀这五个参数是刚性的任何一个不对都连不上。还有一个柔性参数容易被忽略Charset。老版本 MySQL 服务端默认字符集可能是 latin1业务表却可能是 gbk 或 utf8连接层的 Charset 决定客户端和服务器之间的编码约定它必须和服务器端 character_set_client 对齐否则连得上但数据乱。配套的 Options.UseUnicode 也要一起看。置为 True 时字符串在组件层以 Unicode 形式传递能规避一大半乱码问题代价是字符字段都走宽字符路径老代码里如果大量用单字节 String 接收要注意赋值时的隐性转换。我的判断标准新项目无脑开 UseUnicode老项目先查代码里有没有把字符串塞进定长 char 数组的写法再决定开不开。排查时把参数分成两类地址类是硬故障字符集类是软故障。硬故障表现是连不上、报错软故障表现是能连上但数据显示不对。两类问题的排查路径完全不同分清楚能省一半时间。3.2 属性赋值与连接串两种写法、一个共同终点MyDAC 支持两种配置连接的方式逐属性赋值或用一段连接串整体解析。场景不同选型不同。// 方式一逐属性赋值适合配置写在代码里、可读性优先 MyConn : TMyConnection.Create(nil); try MyConn.Server : 192.168.10.5; MyConn.Port : 3306; MyConn.UserName : app_user; MyConn.Password : pssw0rd; MyConn.Database : erp_db; MyConn.Charset : utf8; MyConn.Options.UseUnicode : True; MyConn.ConnectTimeout : 5; MyConn.Connect; finally MyConn.Free; end;这段代码创建独立连接对象填参数后调用 Connect 建立会话。ConnectTimeout 单位是秒设为 5 表示 5 秒内建不成 TCP 连接就报错。这个参数在服务器不可达时特别关键不设置的话默认会一直等到系统级 TCP 超时界面可能卡住十几秒甚至更久。属性赋值的好处是每个参数肉眼可见评审和排错都很直观。// 方式二连接串整体赋值适合配置外置到 ini 或注册表 MyConn : TMyConnection.Create(nil); try MyConn.ConnectString : Server192.168.10.5;Port3306;User IDapp_user; Passwordpssw0rd;Databaseerp_db;Charsetutf8; Use UnicodeTrue;Connect Timeout5; MyConn.Connect; finally MyConn.Free; end;连接串的解析规则是分号分隔的键值对键名大小写不敏感。两种写法最终写入同一组属性不存在谁优先级更高后赋值的覆盖先赋值的。真正的优先级陷阱在设计期对象监视器里填的连接参数会被序列化进窗体 DFM运行时代码再赋值则以代码为准。我处理过一起连错库的故障定位到是 DFM 里残留了开发库的 Database 属性代码里只在某条分支路径上覆盖了连接参数。注意连接配置的来源越少越好。要么全走代码要么全走外部配置文件不要两头都写否则埋下的问题只在特定执行路径上爆发。3.3 最小连接验证用 SELECT 1 把问题切成两半连接配好以后别急着连业务表先跑一个最小验证。这一步能把「连接信息错」和「SQL 写错」两类问题一刀切开。procedure ValidateConnection(AConn: TMyConnection); var Q: TMyQuery; begin Q : TMyQuery.Create(nil); try Q.Connection : AConn; Q.SQL.Text : SELECT 1; Q.Open; // 能走到这里TCP、认证、客户端库三个环节全部通过 ShowMessage(连接正常SELECT 1 Q.Fields[0].AsString); finally Q.Free; end; end;SELECT 1 不触碰业务表不要求账号具备具体表的权限服务器接受登录就能成功。它通过后再执行SELECT DATABASE(), CURRENT_USER()确认当前库和登录账号进一步验证默认库是否正确。这两条语句是我换新环境后必跑的第一组测试。等它们都通过再上业务 SQL此时还有问题责任就在 SQL 本身而不是连接层排查范围立刻缩小一半。4. 读写数据TMyQuery 参数化与 TMyScript 事务配合连接打通进入正题怎么读、怎么写、怎么批量执行。这一章围绕 TMyQuery 的 Open/ExecSQL 选择、参数化传参和 TMyScript 的事务行为展开。4.1 Open 与 ExecSQL 的分工结果集与影响行数TMyQuery 是使用频率最高的数据组件对外暴露两个执行入口选择规则非常固定SELECT 用 Open返回可遍历结果集INSERT/UPDATE/DELETE 用 ExecSQL不返回结果集只返回受影响行数。混用会收到两个方向的报错Open 执行 UPDATE 报语法错误ExecSQL 执行 SELECT 拿不到数据。// 查询走 Open结果集按行遍历 Query.SQL.Text : SELECT order_id, amount FROM orders WHERE create_date :d1; Query.ParamByName(d1).AsDateTime : Date - 7; Query.Open; while not Query.Eof do begin Total : Total Query.FieldByName(amount).AsFloat; Query.Next; end; // 写操作走 ExecSQL用 RowsAffected 做业务校验 Query.SQL.Text : UPDATE orders SET status :st WHERE order_id :id; Query.ParamByName(st).AsInteger : 2; Query.ParamByName(id).AsInteger : 10086; Query.ExecSQL; if Query.RowsAffected 0 then Log(没有行被更新请核对订单号);第一段遍历结果集求和第二段执行更新并通过 RowsAffected 判断命中行数。这里有个高频错误SQL 里参数写成:d1调用时有人写ParamByName(:d1)多了冒号。ParamByName 的参数名不需要冒号带了反而查不到参数对象运行期抛参数不存在。这是代码评审里出现频率最高的低级错误。结果集还有个选项值得提前了解FetchAll。默认情况下 MyDAC 会把结果集一次性取到客户端内存几百行的表没问题几十万行的大查询首屏会明显卡顿。把 FetchAll 关掉、配合 FetchRows 分段取值可以让大数据量查询只取当前需要的部分。代价是连接不能提前关闭游标保持打开状态。用不用取决于业务是「全量处理」还是「翻页展示」全量统计类任务用默认值没问题交互式查询建议按需取。4.2 参数化查询两种传参方式一份防注入保障MyDAC 的参数分命名参数和位置参数。命名参数是默认模式SQL 里写:name调用时用ParamByName(name)赋值位置参数在 SQL 里用?占位调用时用Params[i]按下标赋值。命名参数可读性和可维护性都好一截常规项目没有理由不用它。Query.SQL.Text : SELECT * FROM users WHERE login_name :login AND status :st; Query.ParamByName(login).AsString : EditLogin.Text; Query.ParamByName(st).AsInteger : 1; Query.Open;参数化带来的第一个收益是防注入。字符串拼接写法WHERE login_name EditLogin.Text 用户输入abc OR 11就能改写 SQL 语义参数化把输入当作普通值传给服务器输入内容完全不参与 SQL 解析注入路径从根上堵死。第二个收益是类型边界清晰AsDateTime、AsInteger、AsString 分别告诉组件按什么类型编码日期字段不会再被转成字符串索引也能正常命中。性能习惯也要在这里建立同一句 SQL 反复执行时复用一个 TMyQuery 实例只改参数值再 Open而不是每次新建组件重新解析 SQL。MyDAC 对重复 SQL 文本有预处理缓存复用在批量操作里收益明显。插入几千行数据时一个循环里反复 ExecSQL 同一个查询对象比每次新建对象快一个数量级。4.3 TMyScript 批量执行与事务提交策略多条 SQL 需要按顺序执行成一段脚本时TMyScript 比循环调 TMyQuery 更合适。它接收一整段 SQL 文本内部拆成单条语句顺序发给服务器。Script : TMyScript.Create(nil); try Script.Connection : MyConn; Script.SQL.Text : CREATE TEMPORARY TABLE tmp_sale AS SELECT * FROM sale WHERE dt :d; UPDATE tmp_sale SET status 1; INSERT INTO sale_archive SELECT * FROM tmp_sale;; Script.ParamByName(d).AsDateTime : Date - 1; Script.Execute; finally Script.Free; end;TMyScript 默认把整段脚本放进一个隐式事务任意一条语句失败前面已执行的语句全部回滚。这个默认行为保证了脚本整体原子性但有两个使用边界要记住。第一个边界脚本文本里不要自带 START TRANSACTION、COMMIT 这类事务控制语句。组件层管理事务状态时遇到脚本内嵌事务语句会失去对会话状态的判断后续提交回滚可能落到错误的事务上。第二个边界大批量脚本在单事务里执行时回滚段会膨胀得很快超过 InnoDB 日志限制直接报错。我的一般做法是按批提交每 500 条左右开一个显式事务Commit 后开下一批。每批内原子、批间可恢复既不会丢数据也不会拖垮服务器日志。显式事务本身用 TMyConnection.StartTransaction / Commit / Rollback 控制。默认 Autocommit 模式下每条 SQL 独立提交查询类应用不用额外处理写操作密集时手动开事务把多次写合并成一次提交显著减少磁盘同步次数。事务期间不要夹带长时间 UI 交互长事务持有的行锁会把在线业务堵死这是生产事故的常见来源。5. 避坑排查MyDAC v5.10 最常见的 5 类翻车现场这一章是一线踩坑记录每一条按「现象 → 原因 → 解决」写方便直接对照。前四类是运行期和编译期的高发问题最后一类是发布管理上的通病。5.1 现象程序启动报 libmysql.dll 找不到或加载失败现象编译一切正常程序运行到 Connect 时弹窗提示找不到 libmysql.dll有的环境报的是「无法定位程序输入点」。原因MyDAC 运行期通过动态加载方式调用 MySQL 客户端库dll 不在程序搜索路径下就加载失败。另一种高发原因是客户端库版本和服务器大版本不匹配服务器是 5.7拿的是 4.x 时代的老 dll握手协议对不上表现是能加载但 Connect 报协议错误。dll 属于 MySQL 发行包的一部分不在组件源文件里。解决按服务器大版本取对应 libmysql.dll放到程序 exe 同目录。位数必须匹配32 位程序配 32 位 dll64 位程序配 64 位 dll混用会在加载阶段直接失败。发布目录里把 dll 列为必带文件部署清单上写明从哪个 MySQL 安装目录获取避免现场运维随手找一个版本凑数。5.2 现象中文乱码能连上但读出来全是问号现象数据库里中文正常程序查询结果显示问号或乱码反过来程序写入后再查库库里是乱码。原因连接层字符集和服务器/表字符集不一致。Charset 属性管客户端与服务器通信时的编码约定表的 charset 管存储。表是 utf8 而连接层配成 gbk读取和写入都会按错误规则转换。另一个被低估的原因是 Options.UseUnicode 没开启Delphi 侧字符串按 ANSI 传递遇到多字节字符发生截断。解决先查服务器的 character_set_server、character_set_client 和业务表默认字符集把 MyDAC 的 Charset 配成一致同时把 Options.UseUnicode 置为 True。改完必须做三角验证SELECT 读一条、INSERT 写一条、再 SELECT 读回比对三个环节都正确才算真正解决。很多人只验证了读写入方向还是错的上线后数据进库就花了。5.3 现象程序空闲一段时间后首个查询报 Lost connection现象程序启动后一切正常闲置一会儿再操作第一个查询报「Lost connection to MySQL server during query」或「MySQL server has gone away」。原因MySQL 服务端 wait_timeout 默认 8 小时连接空闲超过该时间被服务器主动断开更短的场景是网络设备或防火墙的空闲老化策略先断了 TCP 连接。MyDAC 侧不实时感知连接已死下次真正发送数据时才收到错误所以表现为「空闲后第一次操作必报错」。解决两层配合。第一层给 TMyConnection 设置合理的 ConnectTimeout避免服务器不可达时界面无响应第二层在业务代码里捕获连接丢失类错误捕获后重建连接再重放最近一次操作。把 wait_timeout 调大治标不治本服务端有连接数上限空闲连接挂太多会耗尽连接数。规范做法是客户端做重连而不是依赖服务器放宽超时。5.4 现象编译源文件时连环报错Unit not found 刷屏现象把 v5.10 源文件放进 IDE 编译报找不到某个单元手动补了搜索路径又报下一个像挤牙膏。原因三类。第一类是 IDE 版本跨代太大源文件的条件编译分支没覆盖新版编译器指令这是硬伤。第二类是库路径只加了子目录漏了源码根目录部分单元在更深层目录里搜不到。第三类是机器上同时存在多套 DCU 产物编译器随机命中旧货报错指向的单元和实际原因对不上。解决先确认源文件包声明支持的 IDE 版本范围硬上太新的 IDE 属于把源码往不兼容环境里塞编译不过不是源码问题。确认兼容后把源码根目录整体加进 Library Path不要只加子目录编译按「连接核心 → 命令层 → 设计期包」依赖顺序逐个来动手前清空所有输出目录排除旧 DCU 干扰。三步走完还报错的把第一个错误信息贴出来按依赖链逐层解决别被后面的报错带偏。5.5 现象设计期连接串被带进生产环境连错库现象程序部署到生产后登录的是开发库或者报密码错误开发环境却一切正常。原因设计期在对象监视器里配置过连接参数尤其是 Database 和 Password这些属性被序列化进了窗体的 DFM 文件。发布时没有清理运行时如果代码里没有显式覆盖程序就按 DFM 里的参数去连。更隐蔽的是连接参数分散在两处DFM 一份、代码一份行为随代码路径变化极难排查。解决从习惯上根治。设计期只填服务器地址和端口这类非敏感参数密码、默认库一律运行时赋值连接信息整体外置到配置文件程序启动时统一读取、统一赋值DFM 里不残留任何连接属性。发布前用文本搜索全量扫描 .dfm 文件确认没有Password字段残留。我把这条写进了发布检查清单每次发版前必跑一次。6. 进阶从 v5.10 源码定位请求链路自己定制通信日志连接、读写、排错都过了一遍最后聊一个能把 MyDAC 从黑匣子变成透明盒子的技巧给组件挂事件把一条 SQL 从发起到返回的完整过程记录下来。MyDAC 的查询从调用 Open 开始内部经过 SQL 解析、参数绑定、发送到服务器、等待响应、按元数据组装字段、逐行取回结果最后才是业务代码拿到数据。想知道链路在哪一段变慢、在哪一段报错最直接的手段是使用 TMyConnection 自带事件。BeforeConnect/AfterConnect 记录建联时刻AfterExecute 看到每条语句执行完成OnError 拿到服务器返回的错误码。把这些事件里的时间点、SQL 文本、执行耗时写进日志就得到了一份请求流水。// 挂到 TMyConnection 的 AfterExecute 事件上记录每条 SQL 的执行耗时 procedure TForm1.MyConnAfterExecute(Sender: TObject); begin LogLine(Format(SQL: %s | 耗时: %d ms, [MyConn.LastCommandText, MyConn.ExecutionTime])); end;LastCommandText 保存最近一次执行的完整 SQL参数值已绑定进去可以直接看到实际发出去的语句ExecutionTime 是本次执行在客户端统计到的总耗时。这两条信息足够区分问题在网络还是服务端SQL 本身很快但总耗时高多半是网络往返多服务器执行慢就要去 MySQL 侧看慢查询日志。比这更底层的手段是直接改源文件在通信缓冲区收发边界打桩打印原始报文。不过这属于牵一发动全身的改动对核心单元的任何修改都会迫使所有依赖包重新编译我通常只在怀疑协议级问题时才动它常规场景挂事件就够了。自己动手做过一次链路记录后再遇到连不上的问题思路会完全不一样不再是猜而是看日志卡在哪一段。这个习惯后来帮我处理过好几起跨网络的疑难连接故障省掉大量来回比对的时间。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询