简介:面向仍在使用 Delphi 7 与 dbExpress 访问 MySQL 5.7 的开发者,这份压缩包提供经过项目实测的 libmysql.dll、dbxopenmysql50.dll 两个关键动态库及配套连接示例,重点解决网上版本杂乱、下载后难以正常连通数据库的问题。包内共 17 个文件,整体约 1.3MB,包含 dll 动态库、pas 与 dpr 源码、dfm 窗体、sql 脚本、dcu 编译单元、exe 演示程序以及 docx 配置说明等,既覆盖 TSQLConnection 可视化配置过程,也保留了可直接运行的测试工程。示例还专门演示如何区分数据库字段为 NULL 还是空字符串,并验证程序在 Windows XP 与 Windows 10 下的运行情况;发布时只需携带 libmysql、dbxopenmysql50 等三个运行库即可。包内另附 SQL 建表脚本与窗体设计文件,便于对照阅读源码结构、复现连接过程,也能作为二次开发的基础工程。已有 827 人学习下载,适合需要快速排查 Delphi 连接 MySQL 5.7 环境配置、动态库匹配与字段判空问题,以及处理旧版本兼容性调试的开发者参考。
1. 一个下午踩两次坑:Delphi 连 MySQL 5.7 到底缺哪两个文件
上周帮人收拾一台要重装的上位机。程序是早年用 Delphi 写的,数据库迁到了 MySQL 5.7,程序拷过去一点开就弹框:Unable to load dbxopenmysql50.dll (error code 126)。把 dll 找齐塞进去,报错换成了Cannot load vendor library [libmysql.dll]。两个文件、两个报错,来回折腾了一下午。
这套组合在维护老项目的圈子里太常见了:Delphi 的 dbExpress 本身不认识 MySQL,得靠额外的驱动 dll(dbxopenmysql50.dll)去桥接 MySQL 的客户端库(libmysql.dll),两个文件都不在安装包里,得单独凑。位数、版本、目录三样有一样对不上,程序就是起不来。这篇按我自己重装环境的顺序写:先对版本,再放文件,再填参数,最后验证——照着走能省掉那个下午。
2. 装前对齐版本:Delphi 位数、MySQL 5.7 和两个 dll 的匹配
动手拷文件之前,有三件事必须先确认清楚:宿主进程是几位、驱动 dll 是几位、客户端库是几位。这三者错一个,后面所有配置都是白费。
2.1 先确定 exe 是 32 位还是 64 位
dbExpress 是进程内加载 dll,dll 的位数必须和宿主进程完全一致,跟操作系统是几位没有关系。64 位的 Windows 上跑一个 32 位的 Delphi 程序,它要的是 32 位的 libmysql.dll,你给它一个 64 位的,加载阶段就直接失败。
判断方法有好几种,我习惯用dumpbin看 PE 头:
# 在 VS 开发者命令提示符里执行,或把 dumpbin 所在目录加进 PATH dumpbin /headers YourApp.exe | findstr /i "machine" # machine (x86) -> 32 位进程,必须配 32 位的 libmysql.dll 和 dbxopenmysql50.dll # machine (x64) -> 64 位进程,两个 dll 都要换 64 位版本/headers读的是 PE 文件头,findstr只筛出机器类型那一行,输出干净。机器上没有 Visual Studio 的话,任务管理器里看进程名后面有没有(32 位)标记,或者用 Process Explorer 看进程属性里的 Image 类型,结论一样。
提示:判断依据永远是宿主进程的位数,不是服务器。MySQL 服务端装的是 64 位版本,你的 32 位客户端程序照样只能用 32 位的 libmysql.dll,这两件事互不影响。
2.2 dbxopenmysql50.dll 在这条链路的什么位置
把调用链摊开看,缺文件时报错为什么会变来变去就清楚了:
TSQLConnection→ dbExpress 核心 →dbxopenmysql50.dll→libmysql.dll→ TCP 3306 → mysqld
Delphi 自带的 dbExpress 只覆盖少数几种数据库,MySQL 不在其中。dbxopenmysql50.dll就是补上的这一层驱动,它把 dbExpress 定义的接口翻译成 libmysql 的 C API 调用。libmysql.dll则是 MySQL 官方客户端库,负责真正的协议握手和数据收发。
所以两个文件缺一不可,缺的位置不同,报错也不同:少了驱动 dll,Delphi 在DriverName这一层就找不到对应的驱动,报的是Unable to load dbxopenmysql50.dll;驱动加载成功但客户端库没到位,报的是Cannot load vendor library。看到哪一句,就知道该查哪一层,不用瞎猜。
至于文件名里的50,通常理解成它对着某一代客户端库接口做的适配。实际以随包说明为准,别拿它去硬配 MySQL 8.0 的 libmysql.dll,认证插件那一关过不去。
2.3 两个 dll 与运行环境的匹配对照
| 运行场景 | 宿主进程 | libmysql.dll | dbxopenmysql50.dll | 说明 |
|---|---|---|---|---|
| 老项目默认编译 | 32 位 | 5.7 系列 x86 版 | 32 位 | 最常见,两个都是 32 位 |
| 新工程改过目标平台 | 64 位 | 5.7 系列 x64 版 | 64 位 | 两个必须同时换,不能一 32 一 64 |
| 同一台机器跑两套程序 | 混合 | 分目录各放一份 | 分目录各放一份 | 别往系统目录里塞,会互相踩 |
| 服务端升到 8.0 | 32 位 | 仍建议用 5.7 的库 | 32 位 | 账号认证插件要改成服务端兼容的那一种 |
表格里最后一行是血泪经验:服务端升到 8.0 之后,账号默认的认证方式变了,5.7 那一代的客户端库不认识新的握手包,表现是连接直接断开、错误信息还很含糊。要么把该账号的认证方式改回 5.7 认识的那一种,要么整套客户端库和驱动一起升级——后者在老项目里通常动不了,只能走前者。
2.4 落地目录怎么摆
确定好位数,把两个文件和程序放成这个结构,这是最省事、也最好排查的一种:
D:\App\ ├─ YourApp.exe ├─ libmysql.dll ├─ dbxopenmysql50.dll ├─ dbxdrivers.ini (可选,运行期读取) └─ dbxconnections.ini (可选,运行期读取)放 exe 同目录有两个好处。一是加载优先级,Windows 在默认搜索模式下会先看 exe 所在目录,再往系统目录走,程序一定能找到自己那一份;二是不污染系统,换版本时删掉重拷就行,不用去System32里翻。
dbxdrivers.ini和dbxconnections.ini不是必须的。如果你的代码里是运行时给Params赋值,这两个文件可以直接不放;只有用设计期的连接编辑器、或者希望不同机器改配置不改代码时,才需要它们,写法在第 4 章。
3. 放置与依赖补齐:让进程真的能找到这两个文件
文件拷过去了还是报 126,八成不是位置问题,而是依赖没齐或者拷错了版本。这一章按「放哪 → 缺什么 → 怎么盯」的顺序走一遍。
3.1 首选方案:跟 exe 放一起
大部分情况下,把两个 dll 复制到 exe 同目录就结束了。这一步没什么技术含量,但有两个细节经常被忽略。
第一个是覆盖问题。目标机器上可能已经有一份旧版本的 libmysql.dll 躺在同目录里,复制的时候提示「是否替换」,顺手点了否,程序跑的其实还是旧的。安装前先看一眼目标目录里有没有同名文件,有就先改名备份再拷。
第二个是只读目录。程序装在Program Files下面的时候,普通用户没有写权限,直接拷文件会失败或者被重定向到虚拟存储。这种场景要么用管理员权限装一次,要么把程序整个目录搬到D:\这种不需要提权的位置——后者我更推荐,老项目的安装包经常没处理好权限。
3.2 系统目录方案:什么时候才用,代价是什么
把 dll 丢进C:\Windows\System32(64 位系统上 32 位程序读的是C:\Windows\SysWOW64)也能跑,但我不建议,除非你确实有多个程序要共用同一份客户端库。
代价有三个。一是版本冲突,另一套程序可能要 8.0 的库,覆盖掉之后你这边又崩了,而且崩得莫名其妙。二是排查困难,出问题时很少有人第一时间想到去系统目录翻 dll。三是卸载不干净,删了程序目录,系统目录里那两份还留着,下次装又撞上。
真要走这条路,务必记住 32 位程序读的是SysWOW64而不是System32,这两个目录名字和实际含义是反的,我第一次配的时候就栽在这里。
3.3 error 126 的另一半原因:libmysql.dll 自己还缺依赖
error code 126的字面意思是「找不到指定的模块」,但它不一定指你缺 libmysql.dll,也可能是 libmysql.dll 缺它自己的依赖。MySQL 5.7 的 Windows 客户端库是 VC++ 2013 那一代工具链编出来的,机器上没装对应的运行库,加载一样失败。
# 看 libmysql.dll 自己依赖哪些运行时库 dumpbin /dependents libmysql.dll # 常见会看到 MSVCR120.dll、KERNEL32.dll、WS2_32.dll 之类 # 如果 MSVCR120.dll 在任何目录下都搜不到,就是运行库没装看到MSVCR120.dll缺失,装一遍对应的 VC++ 运行库即可,这一步在客户机上部署时尤其容易漏。程序在你开发机上好好的,拷到客户机就报 126,九成是这个原因。
注意:运行库要装和 dll 位数一致的那一版。32 位的 libmysql.dll 配 32 位的运行库,装成 64 位的等于没装,报错一模一样。
3.4 用工具盯住加载过程:它到底在找哪个路径
猜不出来的时候别猜,直接看。Process Monitor 加一个过滤器:Process Name is YourApp.exe,再加一条Path contains libmysql,然后启动程序,看输出里标着NAME NOT FOUND的行。
那些行就是进程依次尝试过的路径,从上往下看,最后一条SUCCESS就是它实际加载的位置。如果所有尝试都是NOT FOUND,说明文件确实没在搜索路径里;如果SUCCESS指向了一个你没预期的目录(比如系统目录里的旧版),问题就变成了版本冲突。
这一步花五分钟,能省掉一小时的瞎试。我现在遇到加载类问题基本都先挂上这个过滤器,看一眼就清楚了。
4. 配置 TSQLConnection:dbxopenmysql50 的参数怎么填才生效
文件到位只是让程序能加载驱动,真正连上库还得把TSQLConnection的参数配对。这一章分三块:驱动怎么登记、连接参数怎么给、哪些参数值得调。
4.1 驱动登记:dbxdrivers.ini 里要有这一段
dbExpress 靠一张驱动表来找驱动 dll,这张表存在dbxdrivers.ini里。设计期用的那份一般在 Delphi 安装目录的bin下,运行期读的是 exe 同目录或者用户配置目录下的那一份。不管用哪份,内容长这样:
[Installed Drivers] DbxOpenMySQL50=1 [DbxOpenMySQL50] GetDriverFunc=getSQLDriverMYSQL50 LibraryName=dbxopenmysql50.dll VendorLib=libmysql.dll LibraryNameExp=dbxopenmysql50.dll VendorLibExp=libmysql.dll BlobSize=-1[Installed Drivers]这一段是注册表,DbxOpenMySQL50=1里的 1 表示启用,改成 0 就等于把这个驱动关掉,有时排查「驱动到底有没有被识别」会用到。
[DbxOpenMySQL50]是驱动自己的配置段,段名就是后面DriverName要填的值。GetDriverFunc是驱动 dll 导出的工厂函数名,写错了会报找不到入口点而不是找不到模块,错误信息完全不同,别搞混。LibraryName和VendorLib分别指向驱动 dll 和客户端库,两个都填文件名、不写路径,让系统按搜索顺序去找。
LibraryNameExp和VendorLibExp是给「显式指定库」的写法留的口子,通常和上面两行一致就行。
4.2 连接参数:两种给法,选一种
设计期给参数,就是在dbxconnections.ini里加一段:
[erp_mysql] DriverName=DbxOpenMySQL50 HostName=127.0.0.1 Database=erpdb User_Name=erp Password=erp_pwd BlobSize=-1 Chartset=utf8段名erp_mysql就是后面ConnectionName要填的值。这种写法的好处是换机器只改 ini 不动代码,适合交付给运维同事维护的项目。
运行时给参数更可控,也是我现在更常用的方式:
var Conn: TSQLConnection; begin Conn := TSQLConnection.Create(nil); try Conn.DriverName := 'DbxOpenMySQL50'; // 与 dbxdrivers.ini 的段名严格一致 Conn.LibraryName := 'dbxopenmysql50.dll'; // 驱动 dll,按文件名给,别写绝对路径 Conn.VendorLib := 'libmysql.dll'; // 客户端库 Conn.GetDriverFunc := 'getSQLDriverMYSQL50'; // 驱动导出的工厂函数 Conn.LoginPrompt := False; // 关掉登录框,参数不对时直接抛异常 Conn.Params.Clear; Conn.Params.Add('HostName=127.0.0.1'); // 用 IP,别用主机名,省掉一次 DNS 解析 Conn.Params.Add('Database=erpdb'); Conn.Params.Add('User_Name=erp'); Conn.Params.Add('Password=erp_pwd'); Conn.Params.Add('Chartset=utf8'); // 注意拼写,见 4.3 Conn.Params.Add('BlobSize=-1'); // -1 表示按需分配 Conn.Connected := True; // 到这一步才真正发起连接 finally // Conn 的生命周期自己管,别在这里 Free 掉 end; end;几个参数值得单独说。LoginPrompt := False一定要设,否则参数错了会先弹一个登录框,掩盖掉真正的错误信息,排查时非常误导人。HostName用 IP 而不是机器名,是为了绕开主机名解析,某些内网环境下解析超时会把连接卡住十几秒。Connected := True才是真正建立连接的动作,前面所有赋值都只是准备。
LibraryName和VendorLib写相对文件名就行。写绝对路径的话,换一台机器路径变了又得改代码,反而更麻烦。
4.3 参数取舍:字符集、BlobSize、超时
| 参数 | 建议值 | 作用与取舍 |
|---|---|---|
Chartset | utf8或utf8mb4 | 客户端字符集,拼写就是少个 a,按驱动实际拼写填 |
BlobSize | -1 | 按需分配缓冲,写固定值会让大字段截断 |
Compress | 按网络情况 | 内网没必要开,跨机房可以试,CPU 换带宽 |
ConnectTimeout | 10左右 | 有的驱动版本根本不认这个键,写了不生效也不报错 |
字符集这里有个反复出现的坑:参数名的拼写。按标准写法应该是Charset,但这一代驱动里写的是Chartset,少一个 a。填错的时候不会报错,只是不生效,然后你就看到中文变成问号,还以为是数据库那边的问题。我的做法是照驱动实际支持的拼写填,改完立刻用一条中文数据验证,不要等到上线。
选utf8还是utf8mb4,取决于表里有没有 emoji 或者生僻字。MySQL 5.7 的utf8实际是三个字节的版本,四字节字符存不进去。有这类数据就必须上utf8mb4,同时服务端和表也要一起改,光改客户端参数没用。
BlobSize写-1是省心的做法。写死一个数值(比如 4096),超过的字段会被静默截断,取出来是半截数据,这种 bug 最难查,因为不报任何错。
超时类参数要有心理准备:不是每个驱动版本都支持,写了不生效也不会提示。真正的兜底还是在业务层加超时控制,别指望驱动参数。
5. 避坑清单:六条反复出现的报错和它们的成因
下面这六条是我在不同机器上真的踩过的,按现象、原因、解决三段写,遇到同款直接对照。
5.1 启动就报 error code 126
现象:程序一启动,或者第一次Connected := True时,弹Unable to load dbxopenmysql50.dll (error code 126)。
原因:三种可能——文件没在搜索路径里、文件位数不对、文件自身缺依赖。第三种最容易被忽略。
解决:先用dumpbin /dependents分别看两个 dll 的依赖列表,缺MSVCR120.dll就装运行库;依赖齐了就确认 exe 同目录下确实有这两个文件、位数和进程一致。挂 Process Monitor 看NAME NOT FOUND的路径,能直接定位它找的是哪。
5.2 报 error code 193
现象:报错信息里带error code 193,或者直接提示「不是有效的 Win32 应用程序」。
原因:位数不匹配。32 位进程加载了 64 位的 dll,或者反过来。这个错比 126 更明确,说明文件找到了,就是版本不对。
解决:按第 2.1 节确认宿主进程位数,把两个 dll 一起换成对应位数。注意两个要同时换,只换一个的话,报错会从 193 变成别的,容易误以为没修好。
5.3 连接成功,中文全是问号
现象:Connected正常,查询也返回数据,就是中文显示成???,英文和数字都正常。
原因:客户端字符集没生效。要么参数名拼错(Chartset写成了Charset),要么填的值和服务端、表的字符集对不上。
解决:先确认参数名拼写和驱动要求一致,再执行SHOW VARIABLES LIKE 'character_set_%'看服务端各层字符集。表是utf8mb4而客户端给utf8的情况很常见,四字节字符照样丢。改完用一条确定含中文的记录验证,别看英文数据。
5.4 拿 8.0 的客户端库配 5.7 的服务端
现象:连上去立刻断开,错误信息含糊,说认证失败但密码明明是对的。
原因:MySQL 8.0 默认的账号认证方式和 5.7 不一样,5.7 那一代的 libmysql.dll 不认识新的握手流程。
解决:保持客户端库和服务端大版本一致,5.7 的服务端就用 5.7 的 libmysql.dll。服务端已经升到 8.0 的,把业务账号的认证方式改成 5.7 认识的那一种,别去动驱动。
5.5 设计期能连,编译出来连不上
现象:在 IDE 里点测试连接一切正常,编译出的 exe 跑起来就报加载失败。
原因:设计期用的是 Delphi 安装目录下那份dbxdrivers.ini和那套 dll,编译出的程序读的是 exe 同目录的配置。两边环境不一样。
解决:把dbxdrivers.ini、dbxconnections.ini和两个 dll 都复制到输出目录,或者干脆全部改成运行时赋值,不依赖 ini。我现在新写的代码一律运行时给参数,就是为了避开这个差异。
5.6 本机正常,拷到客户机就崩
现象:开发机上跑了一周没问题,打包发到客户机,一启动就报 126。
原因:客户机缺 VC++ 运行库,或者装过别的软件,系统目录里有一份版本不对的 libmysql.dll 被优先加载了。
解决:安装包里带上运行库,两个 dll 固定放 exe 同目录,别依赖系统目录。交付前在干净的机器上跑一遍第 6 章的三步验证,不要拿开发机当验收环境。
6. 装完怎么验证:三步确认连接真的跑通
文件放好、参数填完,很多人到这一步就收工了,结果交付之后才发现是「能连上但用不了」。我现在的习惯是走完三步再算装完。
第一步,先撇开 Delphi,用命令行确认账号和服务端没问题。
mysql -h 127.0.0.1 -P 3306 -u erp -p -e "select version(), @@character_set_server, @@default_authentication_plugin;"这条命令一次看三件事:服务端版本是不是 5.7、服务端默认字符集是什么、默认认证方式是哪一种。如果这一步就失败,那问题在账号权限或者网络,跟两个 dll 一点关系没有,别在客户端上浪费时间。
第二步,写一个最小的 Delphi 程序,只放一个TSQLConnection和一个TSQLQuery。
Query.SQL.Text := 'select version() as v, @@character_set_connection as cs'; Query.Open; Memo1.Lines.Add(Query.FieldByName('v').AsString); // 期望看到 5.7.x Memo1.Lines.Add(Query.FieldByName('cs').AsString); // 期望和客户端字符集一致 Query.Close;这一步能过,说明驱动加载、客户端库加载、协议握手、字符集协商四关全通了。character_set_connection的值和你填的字符集参数对不上,就是第 4.3 节那个拼写问题。
第三步,用真实数据类型走一遍,别只查select 1。
| 验证项 | 做法 | 通过标准 |
|---|---|---|
| 中文 | 插入一条含中文的记录再读回 | 读回内容与写入一致 |
| 大字段 | 写入超过 64KB 的文本或二进制 | 读回长度一致,无截断 |
| 事务 | StartTransaction后插入再Rollback | 表里没有新增记录 |
| 重连 | 断开后重新Connected := True | 能正常重连,不报错 |
大字段那一项专门用来验证BlobSize=-1有没有生效。事务那一项验证的是驱动对事务的支持程度,某些版本在自动提交上的行为和预期不一样,回滚不掉就很麻烦。
这三步加起来不到二十分钟,但能把后面交付阶段八成的返工挡掉。从那以后我每次换机器部署这套环境,都强制先走一遍这三步,再谈业务功能——「程序能打开」和「数据库真的通了」是两回事,中间隔着的正是那两个 dll 和一堆参数。希望帮到你。
本文还有配套的精品资源,点击获取