多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Delphi 直连 MySQL 实战:MyDAC 源码包编译、连接与避坑指南

Delphi 直连 MySQL 实战:MyDAC 源码包编译、连接与避坑指南 简介本资源为MyDAC v5.00.1.7源码包面向使用Delphi、CBuilder及Kylix进行MySQL数据库开发的中高级程序员。MyDAC是一套可直接连接MySQL服务器或通过客户端库访问的组件库旨在替代标准MySQL连接方案与Borland Database Engine帮助开发者构建更高效、更整洁的数据库应用。压缩包共1297个文件约2.1MB以348个pas源码、134个dpk包定义、128个res资源、105个dfm窗体及84个bdsproj工程文件为主另含cpp、dpr、inc、sql等类型覆盖组件源码、示例工程与编译配置便于二次开发与集成调试。目前已有117人学习下载。通过该源码包读者可深入理解MyDAC的组件架构与直连机制参考示例工程快速搭建数据库访问层并借助源码排查连接与查询问题适合需要定制或研究MySQL数据访问组件的开发者。1. 拆开 mydac.v5.00.1.7.src.rar一套 Delphi 直连 MySQL 的源码包到底能干什么如果你手头有一个老 Delphi 项目数据库是 MySQL而连接层还在用 BDE 或者 ODBC 绕来绕去那你大概率听说过 MyDAC。这次拆的mydac.v5.00.1.7.src.rar就是 MySQL Data Access Components 的源码包版本号 v5.00.1.7里面带MYSQL、MyDAC、MySql.Data src、The Client这些目录线索。它的定位很直接让 Delphi、CBuilder、Delphi for .NET 这些环境不经过 BDE、不经过 ODBC直接跟 MySQL 服务端对话或者走 MySQL 客户端库。包里能看到Global.asax、WebForm.aspx、Make.bat这类文件说明它不只是纯 VCL 组件还带了 Web 侧和构建脚本的痕迹。适合谁适合还在维护 Delphi 存量系统、需要把 MySQL 连接层做薄、想做二次封装或排查底层协议的人。不适合只想拖个控件就完事、完全不看源码的纯新手。2. 源码包结构拆解从 Make.bat 到 The Client 的编译链路拿到一个.src.rar第一反应不该是直接双击安装而是先看清楚它到底给了什么。MyDAC 的源码包和普通组件包不一样它把驱动层、客户端库、构建脚本、Web 示例混在一起目录结构本身就是一份说明书。2.1 目录分层与关键文件定位解压后典型的分层是这样的不同小版本会有微调但主干一致目录/文件作用是否必须Source/核心组件源码含DAC、MyDAC相关单元必须The Client/MySQL 客户端库封装直连与 libmysql 两种模式必须Make.bat批量编译脚本按 Delphi 版本生成包必须Demos/示例工程含 VCL 与 Web 侧建议保留Global.asax/WebForm.aspxASP.NET 侧示例入口按需MySql.Data src托管侧数据访问源码线索按需Make.bat出现多次不是冗余而是针对不同 Delphi 版本比如 D7、2007、2010、XE 系列分别调用dcc32或msbuild。你如果直接跑根目录那个它可能只编一个默认版本编出来的包跟你的 IDE 对不上这就是后面避坑章要说的第一个坑。2.2 直连模式与 Client 模式的区别MyDAC 最核心的选型点在这里它支持两种连接方式。直连模式Direct不依赖libmysql.dll组件自己实现 MySQL 协议。部署时少一个 DLL但协议实现由组件负责遇到新版本 MySQL 的认证插件比如caching_sha2_password可能要先确认兼容性。Client 模式走The Client目录封装的 MySQL 客户端库需要libmysql.dll在位。兼容性跟着官方客户端走但部署多一个文件且 DLL 位数必须和你的程序一致。选哪个我的习惯是内网老系统、MySQL 5.x优先直连省部署要连 MySQL 8 且用到新认证先确认当前 MyDAC 小版本对认证插件的支持不确定就切 Client 模式用官方 DLL 兜底。2.3 用 Make.bat 编译出对应 IDE 的包编译前先确认三件事Delphi 版本、目标平台Win32/Win64、以及dcc32是否在 PATH 里。常见做法是打开命令行进到源码根目录按版本传参。# 进入源码根目录先看 Make.bat 支持哪些参数 type Make.bat # 典型调用指定 Delphi 版本代号与目标平台 # 不同版本代号不同先看脚本里的分支再填 Make.bat D2010 Win32逻辑说明Make.bat内部一般会set一堆路径变量然后对每个.dpk调dcc32。参数说明第一个参数是 IDE 版本代号第二个是平台。如果你传的代号脚本里没有对应分支它可能静默走默认分支编出来的包版本不对装进 IDE 会报“单元版本不匹配”。编译完成后产物是.bpl和.dcu。把.bpl放到 IDE 的包目录.dcu路径加进 Library Path才算是真正装好。只编不装或者只装.bpl不加.dcu路径都会在编译自己工程时报找不到单元。2.4 在工程里挂上连接组件的最小验证装好之后别急着改老工程先建一个空 VCL 工程做最小验证。拖一个TMyConnection设Server、Port、Username、Password、Database然后Connected : True。// 最小连接验证放在按钮事件里 procedure TForm1.btnTestClick(Sender: TObject); begin MyConnection1.Server : 127.0.0.1; MyConnection1.Port : 3306; MyConnection1.Username : testuser; MyConnection1.Password : testpass; MyConnection1.Database : testdb; try MyConnection1.Connected : True; // 触发实际连接 ShowMessage(连接成功服务端版本 MyConnection1.ServerVersion); except on E: Exception do ShowMessage(连接失败 E.Message); // 把原始错误带出来别吞掉 end; end;逻辑说明Connected : True才会真正发起连接前面只是赋值。参数说明ServerVersion能拿到服务端版本用来确认你连的到底是 5.x 还是 8.x这对判断认证插件问题很关键。异常里一定要把E.Message显示出来MyDAC 的报错信息通常包含错误码比“连接失败”四个字有用得多。3. 把 MyDAC 接进真实工程查询、事务与参数化最小连接通了接下来才是真正干活的部分。这一章讲怎么把 MyDAC 用进有查询、有事务、有参数的工程重点在参数化和事务边界这两块出问题最难查。3.1 用 TMyQuery 做参数化查询拼接 SQL 是老工程最常见的写法也是注入和类型错误的源头。MyDAC 的TMyQuery支持参数写法如下。// 参数化查询避免拼接 procedure TForm1.QueryUser(const AName: string); begin MyQuery1.Close; MyQuery1.SQL.Clear; MyQuery1.SQL.Add(SELECT id, name, created_at FROM users WHERE name :name); MyQuery1.ParamByName(name).AsString : AName; // 按名绑定不拼字符串 MyQuery1.Open; while not MyQuery1.Eof do begin Memo1.Lines.Add(MyQuery1.FieldByName(id).AsString - MyQuery1.FieldByName(name).AsString); MyQuery1.Next; end; end;逻辑说明:name是命名参数ParamByName按名赋值MyDAC 负责转义和类型处理。参数说明AsString、AsInteger、AsDateTime要跟字段类型对上用错类型在部分 MySQL 版本上不会报错而是静默转换查出来结果不对这种玄学问题最耗时间。3.2 事务边界与提交回滚MyDAC 的事务通过TMyConnection或TMyTransaction控制。默认可能是自动提交批量写入时如果不显式开事务每条语句一次提交性能差还容易写一半。// 显式事务批量插入要么全成要么全滚 procedure TForm1.BatchInsert; begin MyConnection1.StartTransaction; try MyQuery1.Close; MyQuery1.SQL.Text : INSERT INTO logs(msg) VALUES(:msg); for var i : 1 to 100 do begin MyQuery1.ParamByName(msg).AsString : log- IntToStr(i); MyQuery1.ExecSQL; end; MyConnection1.Commit; // 全部成功才提交 except MyConnection1.Rollback; // 任何一条失败就回滚 raise; end; end;逻辑说明StartTransaction到Commit之间是一个事务边界Rollback保证失败不留半截数据。参数说明ExecSQL用于非查询语句Open用于查询。注意TMyQuery的SQL.Text赋值会清掉旧参数循环里重新赋值参数即可不用每次改 SQL。3.3 连接池与多线程下的注意事项Delphi 老工程里多线程访问数据库是重灾区。MyDAC 的连接对象不是线程安全的一个TMyConnection被多个线程共用轻则报错重则数据错乱。常见做法是每个线程持有自己的连接或者用连接池组件。如果工程规模不大我一般给每个线程在Execute里创建独立连接用完释放。// 线程内独立连接避免共享 procedure TWorkerThread.Execute; var Conn: TMyConnection; Qry: TMyQuery; begin Conn : TMyConnection.Create(nil); Qry : TMyQuery.Create(nil); try Conn.Server : 127.0.0.1; Conn.Username : testuser; Conn.Password : testpass; Conn.Database : testdb; Conn.Connected : True; Qry.Connection : Conn; Qry.SQL.Text : SELECT COUNT(*) FROM users; Qry.Open; // ... 处理结果 finally Qry.Free; Conn.Free; end; end;逻辑说明连接和查询对象都在线程内创建、线程内释放不跨线程共享。参数说明Create(nil)表示无 Owner手动Free。如果一定要共享必须加锁但加锁后并发度就没了不如各自持有连接。3.4 从 BDE/ODBC 迁移过来的字段类型对照老工程迁移时字段类型映射最容易翻车。BDE 的TStringField对应 MySQL 的VARCHAR一般没问题但TDateTimeField和 MySQL 的DATETIME、TIMESTAMP时区处理要留意。BDE/ODBC 侧MyDAC 侧注意点TStringFieldTStringField长度按字符还是字节看字符集TIntegerFieldTIntegerFieldUNSIGNED要确认范围TDateTimeFieldTDateTimeFieldTIMESTAMP受时区影响TBlobFieldTBlobField大字段读取方式不同迁移时先把一个模块跑通对比新旧连接层查出来的数据尤其是时间和金额字段确认无误再铺开。4. 避坑与排查源码包编译和连接层最常见的五个翻车点这一章全是血泪经验。MyDAC 本身是成熟组件但源码包编译和连接配置这两段坑特别集中。4.1 编译报“单元版本不匹配”现象装完包编译自己工程时报Unit ... was compiled with a different version of ...。原因Make.bat编出来的.dcu对应的 Delphi 版本跟你当前 IDE 不一致或者 Library Path 里同时存在多个版本的.dcu。解决确认Make.bat传的版本代号正确编译后把旧的.dcu清掉Library Path 只保留当前版本路径。多个版本共存时路径顺序也会影响加载把当前版本放最前。4.2 直连模式下连 MySQL 8 报认证错误现象Connected : True报认证插件相关错误提示caching_sha2_password之类。原因直连模式自己实现协议老版本 MyDAC 对 MySQL 8 默认认证插件支持不完整。解决先确认当前 MyDAC 小版本是否声明支持该认证插件不支持就切 Client 模式用官方libmysql.dll或者临时把该账号认证方式改成兼容的插件生产环境慎用要评估安全影响。4.3 部署后提示找不到 libmysql.dll现象开发机正常拷到客户机报找不到 DLL 或加载失败。原因Client 模式依赖libmysql.dll位数不匹配或路径不在搜索范围。解决确认 DLL 位数跟程序一致32 位程序配 32 位 DLL把 DLL 放到 exe 同目录或加进系统 PATH。直连模式则不需要这个 DLL部署前先确认用的是哪种模式。4.4 中文乱码现象查出来中文是问号或乱码。原因连接字符集跟库表字符集不一致。解决在连接参数里显式设字符集常见做法是设成utf8mb4跟库表对齐。改完重启连接再测别在旧连接上改。4.5 事务没生效数据写一半现象批量操作中途失败库里留了半截数据。原因没显式开事务或者用了不支持事务的存储引擎比如 MyISAM。解决确认表引擎是 InnoDB代码里显式StartTransaction/Commit/Rollback。迁移老库时特别要查引擎MyISAM 上开事务是无效的这个坑很隐蔽。5. 进阶把 MyDAC 源码包变成可维护的连接层走到这一步连接能通、查询能跑、坑也避了剩下的是怎么让它长期可维护。我的习惯是不在业务代码里到处散落TMyConnection而是收一层。5.1 封装一个连接工厂// 简单连接工厂集中管理连接参数 function CreateConnection: TMyConnection; begin Result : TMyConnection.Create(nil); Result.Server : 127.0.0.1; Result.Port : 3306; Result.Username : testuser; Result.Password : testpass; Result.Database : testdb; Result.LoginPrompt : False; // 不弹登录框避免无人值守卡住 end;逻辑说明参数集中一处改连接信息不用满工程搜。参数说明LoginPrompt : False在服务端或定时任务里必须设否则弹框会卡死进程。5.2 用源码调试定位协议层问题源码包最大的价值是能跟进去。连接异常时在The Client相关单元里下断点能看到实际发出的握手包和错误码比只看异常信息清楚得多。这一步不需要改源码只要能编译带调试信息的包即可。5.3 版本升级前的验证清单验证项方法通过标准连接建立最小工程连目标库无异常版本正确参数化查询跑带参数的增删改查结果与预期一致事务回滚故意制造失败数据无残留中文读写写入再读出中文无乱码多线程并发跑查询无共享冲突报错每次升级 MyDAC 小版本这张表走一遍比出事再查省时间。从那以后我每次换连接层版本都强制走一遍这个清单再急也不跳。希望帮到你。本文还有配套的精品资源点击获取
返回列表