ARTICLE DETAIL

资讯详情

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

老Delphi连接MySQL 5.7:libmysql与dbxopenmysql50.dll配对指南

老Delphi连接MySQL 5.7:libmysql与dbxopenmysql50.dll配对指南 简介针对Delphi 7通过dbExpress连接MySQL 5.7的实际开发需求该资源提供作者亲测可用的libmysql.dll和dbxopenmysql50.dll驱动组合及完整测试用例解决了老版Delphi适配新版MySQL时常遇到的动态库不兼容、网上驱动不可用等问题并附有数据库空值与空字符串的区分演示。安装包共17个文件含两个核心DLL、可执行测试程序、SQL脚本、Delphi工程源码及TSQLConnection可视化配置说明整体仅1.3MB可在Windows XP与Windows 10下运行发布时仅需libmysql、dbxopenmysql50和midas三个库。该方案已有822人次浏览学习适合使用Delphi 7维护或开发MySQL 5.7应用的开发人员直接参考复用。1. 老 Delphi 连不上 MySQL 5.7先别急着改代码接手一个维护了三五年的老 Delphi 项目最怕遇到的环境问题之一就是数据库从 MySQL 5.1/5.5 迁到 MySQL 5.7 之后原先好用的连接代码突然开始报错。我见过不少人上来就翻源码把 TSQLConnection 的属性来回改改到最后发现问题根本不在代码而是 dll 这一层的版本组合不对。标题里提到的 libmysql 和 dbxopenmysql50 两个动态库就是这条链路里最容易掉链子的两环一个是 MySQL 官方客户端库负责跟服务器完成握手一个是 dbExpress 的驱动实现负责把 Delphi 的 SQL 请求转交给客户端库。这套组合配好之后连接代码几乎不用动。这篇文章会把两个文件的角色分工、部署位置、最小能跑的配置步骤以及最常坑人的五个场景一次讲透给正在做老项目维护的人当一份可以直接对照的检查清单。对新手上路的人来说这套方案比自己去下载 mysql5.7 全套服务端再编译折腾要稳妥得多花十几分钟把环境理顺后面通过数据库读写数据就是顺理成章的事。2. dbExpress 的驱动关系为什么必须有两个 dll 而不是一个2.1 前台与后台的分工驱动库和客户端库各管一段要弄明白为什么需要两个 dll得先从 dbExpress 的架构说起。dbExpress 是 Borland 时代提出的跨数据库访问框架设计初衷是轻量、单向、不维护缓存和更老一代的 BDE 相比它把“连接数据库”这件事拆成了两层。第一层是 dbxopenmysql50.dll它属于 dbExpress 的 MySQL 驱动。Delphi 在运行时会通过 LoadLibrary 把这个 dll 加载进进程然后调用它内部导出的入口函数再经由它去操作第二层的库。第二层是 libmysql.dll这是 MySQL 官方发布的 C 语言客户端库处理 TCP 连接、协议握手、SQL 命令封装和结果集返回。dbExpress 自己不直接跟 MySQL 服务器对话它只负责把 Delphi 侧的对象调用翻译成 MySQL C API 的函数调用。换句话说dbxopenmysql50.dll 是翻译官libmysql.dll 是具体干活的工人少了任何一个都没法完成连接。这个设计沿袭到后来的很多框架里比如 FireDAC 也会有一个类似的前后台结构。理解这一点对排查问题是决定性的报错信息如果提到 “Cannot load driver” 或者 “Driver not recognized”通常嫌疑在 dbxopenmysql50.dll 这一层如果报错信息是 “Cant connect to MySQL server” 或者弹窗里直接出现 libmysql.dll 的名字那问题就在第二层。2.2 “50”不是 MySQL 5.0而是驱动协议版本标识很多人第一次看到 dbxopenmysql50.dll 都会误以为它只支持 MySQL 5.0甚至据此认为必须找一个叫 dbxopenmysql57.dll 的东西。实际上文件名的 “50” 是 dbExpress 驱动内部的版本标识它对应的是驱动接口协议的代号不是 MySQL 的主版本号。从 MySQL 5.0 到 5.7libmysql.dll 对外导出的核心 API 基本保持兼容所以 dbxopenmysql50.dll 可以被用来连接 5.7 的服务端。但这不代表随便拿一个 libmysql.dll 就能配合工作。dbxopenmysql50.dll 内部是按某个特定范围的 libmysql API 版本去调用的MySQL 官方客户端库在演进过程中虽然保留旧接口但部分结构体和函数签名有细微调整。常见现象是拿 MySQL 5.0 时代的 libmysql 去连 5.7 服务器连接建立后会出一些稀奇古怪的协议错误或者 SELECT 结果乱码。反过来拿 MySQL 8.0 的 libmysql 塞给 dbxopenmysql50.dll也可能因为调用约定或内部结构变化导致加载失败。所以这套 zip 之所以被反复传播核心价值就是“配对经过验证”。我不主张把所有 dll 全部混在一起用而是建议以这个组合为基线确认连接正常后再做二次开发。如果客户机器上另外装有 MySQL 服务端直接复制安装目录里的 libmysql.dll 过来也常常是可行的但必须确认位数一致这一点是下面要展开的关键。2.3 DLL 搜索顺序与 32/64 位问题动手前必须明确Windows 加载动态库时有一个搜索顺序应用程序 exe 所在目录优先然后是当前工作目录、系统目录、PATH 环境变量里的路径。老 Delphi 7 时代很多工程直接把两个 dll 扔进 C:\Windows\System32这在 32 位 Windows 上没问题但放到 64 位 Windows 上就会踩一个大坑System32 目录被系统重定向给 64 位程序使用而 32 位程序访问 System32 时会被转到 C:\Windows\SysWOW64这个目录才是存放 32 位系统库的地方。于是同一个路径不同的程序会看到不同的物理文件造成“我明明放进去了但程序还是说找不到”的错觉。更麻烦的是位数匹配。MySQL 官方发布的 libmysql.dll 有 32 位和 64 位两个版本而老 Delphi 编译器生成的是 32 位程序只能加载 32 位 dll。如果你从一台 64 位 MySQL 服务器安装目录里拷出 64 位 libmysql.dll 给 Delphi 程序用LoadLibrary 阶段可能不报错但一调用导出函数就会触发“无法定位程序输入点”或者“应用程序无法启动”。这个问题的排查难点在于它和代码无关换成任何连接配置都一样报错。我一般会把两个 dll 直接放到 exe 旁边而不是放系统目录。这样既绕开了 SysWOW64 重定向和杀毒软件对系统目录写入的敏感拦截也让部署更干净。下面一节就按这个习惯给出一套可以照做的部署流程。文件角色常见误用dbxopenmysql50.dlldbExpress MySQL 驱动误认为只支持 MySQL 5.0libmysql.dllMySQL 官方客户端库直接拿 64 位版给 Delphi 加载两个文件放系统目录依赖全局路径64 位系统重定向、被安全软件拦截3. 部署与最小连接步骤目录、ini、TSQLConnection 一次配好3.1 文件摆放与全局搜索路径这套方案的落地第一步是文件摆放。拿 exe 作为基准目录把 dbxopenmysql50.dll 和 libmysql.dll 放进 exe 同层目录这是最稳的姿势。开发机上有多个项目时也可以放到一个公共目录然后把这个目录加进系统 PATH。但要注意PATH 方案只适合自己开发机给客户部署时客户机器上不一定有那个目录所以正式发布我还是建议走 exe 同层路径。放好之后可以用一个小办法确认两个库能被系统正常加载打开命令行切到 exe 所在目录执行dir看一下文件是否在然后在工程里加一句 LoadLibrary 测试。Delphi 侧可以用下面的代码片段直接验证加载能力procedure TFormMain.VerifyDllClick(Sender: TObject); var hDriver: THandle; hVendor: THandle; begin // 测试驱动库是否可加载 hDriver : LoadLibrary(PChar(dbxopenmysql50.dll)); if hDriver 0 then raise Exception.Create(dbxopenmysql50.dll 加载失败请检查文件位置和位数); // 测试客户端库是否可加载 hVendor : LoadLibrary(PChar(libmysql.dll)); if hVendor 0 then raise Exception.Create(libmysql.dll 加载失败请检查文件位置和位数); // 加载成功后释放句柄 FreeLibrary(hDriver); FreeLibrary(hVendor); end;这段代码的逻辑是先用 LoadLibrary 把两个 dll 拉进当前进程返回 0 就说明系统在这个目录下找不到文件、或者文件依赖的系统运行库缺失。注意 LoadLibrary 成功不代表函数可调用但至少排除了路径和基础依赖问题。完成后记得 FreeLibrary 释放句柄避免后续 dbExpress 加载时出现句柄重复占用的问题。3.2 用 ini 文件把驱动参数固定下来dbExpress 在 Delphi 7 时代依赖两个配置文件dbxdrivers.ini 描述驱动本身的信息dbxconnections.ini 描述具体的连接参数。程序首次创建 TSQLConnection 时会读取这些配置。很多老工程在安装时会把这两个 ini 写到系统公共目录但部署到新机器时经常遗漏导致找不到驱动。稳妥做法是在工程目录保留一份 dbxdrivers.ini并在发布包里和 exe 一起输出。关键段落按下面的结构写[MySQL] DriverNameMySQL LibraryNamedbxopenmysql50.dll VendorLiblibmysql.dll GetDriverFuncgetSQLDriverMYSQL这里四个字段的作用分别是DriverName 是连接组件里引用的逻辑名称LibraryName 指定驱动 dllVendorLib 指定客户端库 dllGetDriverFunc 是 dll 内部导出的入口函数名。GetDriverFunc 不要随意改dbxopenmysql50.dll 导出这个函数的符号名为 getSQLDriverMYSQL大小写和写法必须与 ini 里完全一致。如果程序仍然提示找不到驱动再查一下这个 ini 是否被系统路径下的同名文件抢先读取了。注意全局搜索顺序里 exe 目录优先于系统目录但要排除一种情况开发环境里 IDE 的 Tools 菜单中设置了额外的库路径时Delphi 可能先从 IDE 配置里读取 dbx 配置这一点在调试时要留意。3.3 TSQLConnection 最小连通代码配好 ini 之后Delphi 侧的连接代码可以做到很短。建立一个新窗体放一个按钮在 OnClick 事件写下面的代码procedure TFormMain.ButtonConnectClick(Sender: TObject); var Conn: TSQLConnection; begin Conn : TSQLConnection.Create(nil); try // 指定驱动逻辑名与 dbxdrivers.ini 中的 DriverName 保持一致 Conn.DriverName : MySQL; // 参数值按实际环境修改 Conn.Params.Values[HostName] : 127.0.0.1; Conn.Params.Values[Port] : 3306; Conn.Params.Values[Database] : demo; Conn.Params.Values[User_Name] : root; Conn.Params.Values[Password] : your_password; Conn.Params.Values[BlobSize] : -1; // Open 方法触发 dbExpress 加载 dll 并建立连接 Conn.Open; ShowMessage(连接成功服务器版本 Conn.ServerVersion); finally Conn.Free; end; end;这里的逻辑顺序是先创建 TSQLConnection 实例然后指定 DriverName 告诉 dbExpress 用哪个驱动再填充连接参数最后调用 Open 触发真正的加载和握手。ShowMessage 里读取的 ServerVersion 来自 dbExpress 驱动内部能显示出来就说明驱动库和客户端库都已经正常工作。BlobSize 设为 -1 表示按驱动默认的缓存大小处理不用手动限制。需要注意Password 里如果有特殊字符ini 文件里要避免与分隔符冲突直接在代码里赋值更省心。3.4 连接参数速查表下面给出一张在实际项目中常用的参数表覆盖连接阶段最常涉及的字段。数据库名、端口这些大家都很熟重点提示一下容易被忽略的属性。参数名典型值说明常见坑HostName127.0.0.1MySQL 服务器地址填 localhost 时部分老驱动走 socket 而服务器配置 tcp 时失败Port3306TCP 端口改了 my.ini 端口后这里要同步Database库名目标数据库不填也能连但查询时容易选错库User_Nameroot用户名老驱动对 mysql_native_password 支持好对 caching_sha2_password 支持不完整Password用户密码认证凭据包含分号等字符时注意转义BlobSize-1大数据字段缓冲区设为 32 会导致大字段读取异常CharSetutf8字符集设置老驱动未必识别该参数更多靠连接后 SET NAMES其中 User_Name 与密码的验证方式值得单说一句。MySQL 5.7 默认的认证插件是 mysql_native_passworddbxopenmysql50.dll 配合 libmysql.dll 能正常处理。如果服务器侧迁移到 MySQL 8.0 且用户调整为 caching_sha2_password老客户端库大概率不支持连接时会被服务器拒绝。这也是为什么许多老项目宁可留在 5.7 也不愿直接升 8.0 的底层原因之一。3.5 通过 TSQLQuery 做一次真实查询连接能打开之后还要验证数据链路能完整走通。写一个最简单查询用 TSQLQuery 从系统表里取当前字符集和版本信息procedure TFormMain.TestQueryClick(Sender: TObject); var Conn: TSQLConnection; Q: TSQLQuery; begin Conn : TSQLConnection.Create(nil); Q : TSQLQuery.Create(nil); try Conn.DriverName : MySQL; // 连接参数省略可复用前面的赋值方式 Conn.Open; Q.SQLConnection : Conn; Q.SQL.Text : SELECT VERSION() AS ver, character_set_server AS cs; Q.Open; ShowMessage(版本 Q.FieldByName(ver).AsString #13#10 服务器字符集 Q.FieldByName(cs).AsString); finally // 先释放数据集再释放连接顺序反过来会泄漏句柄 Q.Free; Conn.Free; end; end;这段代码验证两件事一是 SELECT 能正常返回数据二是 dbExpress 能把结果集字段正确映射到 Delphi 侧。FieldByName 拿到的是字符串类型显示服务器字符集会直接暴露服务端默认配置。最后释放对象时注意先释放 Q 再释放 Conn因为数据集还引用着连接对象顺序反了在极端情况下会引发非法指针访问。4. 最常见的五个翻车现场报错、原因与处置顺序4.1 报 Cannot load driver 时先查 ini 指向而不是重装现象运行连接代码弹窗提示 “Cannot load driver MySQL”。很多人第一反应是重装 Delphi 或者重新安装 MySQL 客户端但根本原因通常更简单。原因dbxdrivers.ini 里 LibraryName 指向的 dbxopenmysql50.dll 不在搜索路径下或者 GetDriverFunc 拼写错误。也可能是 IDE 里跑程序时当前工作目录不在 exe 目录而在 Delphi 的 bin 目录导致 dll 找不到。解决把两个 dll 复制到 exe 同层目录并在代码开头临时输出一次 GetCurrentDir确认运行目录和 exe 目录一致。再核对 ini 配置里的 LibraryName 与 VendorLib 文件名注意扩展名 .dll 不能遗漏。开发调试时可以在 Project Options 里把 Working Directory 设为 debbug 输出目录。4.2 libmysql.dll 无法定位程序输入点九成是位数不匹配现象报错文字直接提到 libmysql.dll 中找不到某个函数入口比如 GetMinimalSocketAddress 之类点确定后程序终止。这类弹窗出现在 Windows 自带的错误报告里看起来不像 Delphi 的异常。原因32 位 Delphi 程序加载了 64 位 libmysql.dll。load 过程可能并不立即失败直到 dbExpress 驱动内部调用某个导出函数时Windows 才发现函数地址无法解析。这种情况在从 64 位 MySQL 服务端目录复制 libmysql 时频繁发生。解决确认获取的是 32 位版本的 libmysql.dll。判断方式有几种右键文件属性看版本信息里的平台用 depends 工具查看 PE 头或者看文件大小64 位版本通常比 32 位大一些但不绝对。最简单的做法是直接使用 zip 里这一套搭配好的文件不要混搭。4.3 报 Unable to Connect 后问题通常不在 dll 而在服务端现象驱动加载成功但 Open 时提示 “Unable to Connect to the Database” 或直接超时。原因libmysql.dll 已经能跟服务器建立 TCP 会话但 MySQL 服务端没有监听预期端口或者 my.ini 配置了 skip-networking只允许本地 socket 连接。还有一种常见情况是 bind-address 绑定了 127.0.0.1而客户端从别的机器访问自然连不上。解决先从命令行用 mysql 客户端确认本机可连再确认远程访问是否存在网络限制。用 telnet 或 PowerShell 的 Test-NetConnection 检查 3306 端口。如果服务器配置了 bind-address需要改成 0.0.0.0 或增加一个绑定的网卡地址改完重启 MySQL 服务。这里消耗的时间经常比排查 dll 还长因为方向容易跑偏到代码层。4.4 中文乱码老驱动的字符集默认值问题现象查询出的中文显示成 ?? 或乱码但数据本身在 MySQL Workbench 里看是正常的。原因dbxopenmysql50.dll 连接 MySQL 时初始的 character_set_results 通常沿用服务器端默认值也就是 latin1 或 utf8。而数据表可能已经是 utf8mb4导致客户端拿到的字节流和 Delphi 侧字符串解释方式不一致。老驱动对 utf8mb4 的支持尤其不稳定。解决连接成功后立即执行一次SET NAMES utf8mb4然后再做查询。可靠的做法是把这行 SQL 放在 TSQLConnection 的 AfterConnect 事件里或者干脆封装到一个公共函数中所有查询前先调用。需要说明的是Charset 参数在某些版本里不生效用 SET NAMES 是更底层的保障。另外还要检查数据库表和字段自身的字符集表是 latin1 而列是 utf8mb4 也会乱。4.5 在客户机上换目录就失效运行库依赖与安全软件拦截现象开发机测试通过部署到客户机后无法连接报错要么是找不到 dll要么是缺少某个系统运行库。原因dbxopenmysql50.dll 本身依赖 Delphi 的运行库但客户机往往没有libmysql.dll 还依赖微软的 VC 运行库。还有一个隐蔽因素部分安全软件会把 dll 从系统目录隔离或拦截加载导致程序在客户机上表现和开发机完全不同。解决发布包里带上两个 dll 之外还要考虑混用 VC 运行库。手头没有可靠判断工具时可以先在客户机手动注册或直接打开 dll 看依赖。部署时尽量把文件放 exe 目录而不是系统目录避免安全软件对全局写入的动作更敏感。如果客户机已经能跑其他基于 dbExpress 的软件那大概率运行库是齐全的可以集中查 dll 版本。5. 部署到客户机器验证加载与免安装分发的做法5.1 用 SELECT 结果反推 dll 是否正常工作部署完成后最好的验证不是看弹窗提示而是看一条真实查询能否返回正确内容。我习惯在发布包里留一个简单的诊断程序或者给连接按钮加一段只读版本信息的逻辑让现场人员在启动页面顺手点一下。这样可以一次性确认三个环节dll 能加载、连接能建立、SQL 能返回。借助上一节提到的 TestQueryClick 代码客户机上点击后能看到版本号和字符集基本就能放心进入业务功能测试。如果版本号显示正常但中文仍是乱码优先检查SET NAMES是否执行成功。可以用同一个 TSQLQuery 执行SHOW SESSION VARIABLES LIKE character_set_results把结果一并展示出来。现场人员不需要理解细节照着截图反馈即可。这个诊断做法在熟手手里十分钟解决在业务方手里也能减少来回沟通成本。5.2 免安装目录和最小发布集合的取舍给客户机器做免安装部署时我把发布文件控制在尽量小的范围exe、两个配置文件、两个 dll再加上业务需要的其他文件。dbxdrivers.ini 和 dbxconnections.ini 必须和 exe 放同层或者通过代码显式指定路径否则客户机器上的全局配置会干扰连接行为。曾经遇到过客户机器同时装了另一套系统的场景该系统的 dbxconnections.ini 里有同名连接配置导致我的程序读到了对方的数据库参数。后来统一改成在程序启动时用 TSQLConnection 的直接赋值方式覆盖关键参数不再信任全局 ini 的内容。这是一个很值得养成的习惯ini 作为驱动配置参考而 HostName、UserName、Password 等环境相关参数写在程序自己的配置文件里发布时单独管理。新的 Delphi 项目其实不值得再走这套老路FireDAC 对 MySQL 5.7 和 8.0 的支持完整得多字符集和认证插件都处理得更好。但老项目既然已经在 dbExpress 上稳定跑了多年换框架的回归成本往往高于 dll 带来的维护成本这也是这套方案在 5.7 时代仍然被大量搜索和使用的现实原因。希望这篇能帮你把两个 dll 一次摆平连接稳定之后记得把版本组合记录在项目 notes 里避免半年后接手的人再踩一遍同样的坑。本文还有配套的精品资源点击获取
返回列表