news 2026/10/4 1:04:42

PyQt5连接MySQL报Driver not loaded的完整排查与解决

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyQt5连接MySQL报Driver not loaded的完整排查与解决

1. 这个报错不是代码写错了,而是PyQt5根本没“看见”MySQL驱动

你刚在PyQt5里写下这行代码:

db = QSqlDatabase.addDatabase("QMYSQL") db.setHostName("localhost") db.setDatabaseName("testdb") db.setUserName("root") db.setPassword("123456") if not db.open(): print(db.lastError().text())

运行后控制台只甩给你一句冰冷的Driver not loaded—— 没有堆栈、没有路径提示、没有具体模块名,连个错误码都懒得给。你翻遍自己写的逻辑,确认host、port、user、password全对;用命令行mysql -u root -p能正常登录;Navicat连得稳稳当当;甚至用pymysql或mysql-connector-python写个简单脚本也能查出数据……可偏偏 PyQt5 就是死活加载不了驱动。

这不是你的代码问题,也不是MySQL服务的问题,更不是密码输错了——这是 PyQt5 的数据库驱动加载机制和你本地环境之间的一场“失联”。它不像 Python 的import pymysql那样靠sys.path查找模块,也不像 Java 的 JDBC 那样靠 classpath 加载 jar 包。PyQt5 的QSqlDatabase是通过 Qt 的插件系统(Plugin System)在运行时动态加载.dll(Windows)或.so(Linux/macOS)文件的,而这个加载过程完全脱离 Python 解释器的控制范围,发生在 C++ 层。一旦 Qt 找不到对应驱动的二进制文件,或者文件依赖缺失、架构不匹配、路径未注册,它就只会吐出那句万能又无用的Driver not loaded。

我第一次遇到这个问题是在部署一个内部资产管理系统时。开发机上一切正常,打包成 exe 后发给同事,双击就弹窗报错。同事反复重装 PyQT5、重装 MySQL、重配环境变量,折腾三天毫无进展。最后发现:他电脑上装的是 MySQL 8.0.33 的 x64 安装版,而我打包用的 PyQt5 是从pip install PyQt5==5.15.19装的官方 wheel,它自带的qsqlmysql.dll只链接了 MySQL 5.7 的libmysql.dll。同事机器上根本没有libmysql.dll,系统 PATH 里也没有指向 MySQL 安装目录的 bin 文件夹——Qt 插件加载器在C:\Windows\System32、C:\Python39\Library\plugins\sqldrivers、exe所在目录\sqldrivers这几个固定位置翻了个底朝天,最终两手一摊:“Driver not loaded”。

所以,别急着改 Python 代码。先问自己三个问题:

  • 你的 PyQt5 是怎么装的?是 pip 官方 wheel?conda?还是从源码编译?
  • 你的 MySQL 是怎么装的?是官网下载的 MSI 安装包?zip 免安装版?还是通过 XAMPP/WAMP 附带的?
  • 你的操作系统是 32 位还是 64 位?Python 是 32 位还是 64 位?MySQL 是 32 位还是 64 位?这三个“位数”必须严格一致,差一位,qsqlmysql.dll就会因 ABI 不兼容而被 Qt 直接忽略。

这个报错的本质,是 Qt 的插件加载器在执行QLibrary::load()时失败了,而失败原因被 Qt 封装成了统一的字符串。它不告诉你缺了哪个 DLL,不告诉你路径在哪,甚至不告诉你当前搜索了哪些目录——它只负责“加载失败”,把解释权留给了开发者。接下来我们要做的,就是绕过这个黑箱,亲手把它撬开。

2. 驱动加载的完整路径:从 Qt 插件目录到 libmysql.dll 的生死链

要真正解决Driver not loaded,你必须理解 Qt 加载数据库驱动的完整链条。这不是一个简单的“复制文件到某目录”就能搞定的操作,而是一条环环相扣的依赖链。我们以 Windows 系统为例(Linux/macOS 原理相同,只是文件扩展名和路径分隔符不同),拆解这条链路上每一个关键节点。

2.1 Qt 插件目录:驱动文件的法定“户籍所在地”

Qt 在启动时会扫描一系列预设目录,寻找sqldrivers子目录,并从中加载.dll文件。这些目录按优先级从高到低排列如下(可通过QApplication.libraryPaths()查看):

优先级目录路径说明
1./sqldrivers(当前可执行文件所在目录下的子目录)打包工具(如 PyInstaller)最常放驱动的地方,最高优先级,也是最推荐的部署方式
2./plugins/sqldrivers(当前可执行文件所在目录下的 plugins 子目录)传统 Qt 应用常用结构
3C:\Python39\Lib\site-packages\PyQt5\Qt5\plugins\sqldriverspip 安装 PyQt5 时的默认位置,但仅对直接运行 .py 文件有效,对打包后的 exe 无效
4C:\Users\<user>\AppData\Local\Programs\Python\Python39\Lib\site-packages\PyQt5\Qt5\plugins\sqldrivers用户级安装路径,同上
5C:\Qt\5.15.2\mingw81_64\plugins\sqldrivers如果你单独安装了 Qt SDK,这里也会被扫描

提示:qsqlmysql.dll必须放在上述任意一个sqldrivers目录下,且文件名必须是qsqlmysql.dll(Windows)、libqsqlmysql.so(Linux)或libqsqlmysql.dylib(macOS)。Qt 不会识别mysql.dll或qsql_mysql.dll这样的变体。

我曾见过一个项目,开发者把qsqlmysql.dll放在了./libs/目录下,然后在代码里调用QApplication.addLibraryPath("./libs")。这完全无效——addLibraryPath()添加的是 Qt 插件的根目录(即包含sqldrivers、imageformats等子目录的父目录),而不是sqldrivers本身。正确做法是QApplication.addLibraryPath("./libs/plugins"),前提是./libs/plugins/sqldrivers/下有qsqlmysql.dll。

2.2 qsqlmysql.dll:Qt 的 MySQL 驱动桥接器

qsqlmysql.dll本身并不实现 MySQL 协议,它只是一个轻量级的“胶水层”,负责将 Qt 的QSqlDriver接口调用,翻译成对底层 MySQL C API 的调用。因此,它必须链接(link)到真正的 MySQL 客户端库——libmysql.dll(Windows)或libmysqlclient.so(Linux)。

这个链接关系是静态链接还是动态链接,取决于你使用的 PyQt5 版本和构建方式:

  • 官方 pip wheel(如 PyQt5-5.15.19):qsqlmysql.dll是动态链接到libmysql.dll的。这意味着它在运行时必须能找到libmysql.dll,否则加载失败。
  • conda 安装的 PyQt5:通常会把libmysql.dll打包进 conda 环境的Library\bin目录,并通过修改PATH环境变量确保其可见。
  • 从源码编译的 PyQt5:你可以选择静态链接(--static参数),这样qsqlmysql.dll就不再依赖外部libmysql.dll,但体积会增大,且无法热更新 MySQL 客户端。

验证qsqlmysql.dll是否动态链接libmysql.dll,最直接的方法是用Dependency Walker(Windows)或ldd(Linux)工具查看其导入表。在 Windows 上,右键qsqlmysql.dll→ “属性” → “详细信息”标签页,如果“产品名称”显示为 “PyQt5” 而非 “Qt Project”,基本可以确定它是 pip wheel 版本,需要libmysql.dll。

2.3 libmysql.dll:MySQL 客户端库的“命门”

libmysql.dll是 MySQL 官方提供的 C API 客户端库,所有基于 MySQL C API 的语言绑定(包括 Qt 的qsqlmysql.dll、Python 的pymysql底层、甚至某些 PHP 扩展)都依赖它。它的版本必须与你的 MySQL 服务器向后兼容,但不能跨大版本跳跃。

MySQL 服务器版本推荐的 libmysql.dll 版本兼容性说明
MySQL 5.7.xMySQL 5.7.x 安装包自带的libmysql.dll最稳定,官方 wheel 默认链接此版本
MySQL 8.0.xMySQL 8.0.x 安装包自带的libmysql.dll必须使用 8.0.x 版本,5.7 的libmysql.dll无法连接 8.0+ 服务器(认证插件变更)
MySQL 8.4+MySQL 8.4.x 安装包自带的libmysql.dll新增了对 caching_sha2_password 的原生支持

注意:libmysql.dll的位数(32/64)必须与qsqlmysql.dll和 Python 解释器完全一致。一个 64 位的qsqlmysql.dll去加载 32 位的libmysql.dll,结果必然是ERROR_BAD_EXE_FORMAT,而 Qt 会将其统一包装为Driver not loaded。

最常见的错误场景是:你装了 MySQL 8.0.33 的 64 位 MSI 安装包,它把libmysql.dll放在了C:\Program Files\MySQL\MySQL Server 8.0\lib目录下。但这个目录不在系统 PATH 中,Qt 加载器找不到它。于是你手动把libmysql.dll复制到C:\Windows\System32(64 位系统)或C:\Windows\SysWOW64(32 位系统),以为万事大吉。结果发现,qsqlmysql.dll依然报错。为什么?因为libmysql.dll自身还有依赖!它需要VCRUNTIME140.dll、MSVCP140.dll(Visual C++ 2015-2019 运行库)等。如果你的机器没装 VC++ 运行库,或者版本太旧,libmysql.dll本身就加载失败,qsqlmysql.dll自然也跟着失败。

2.4 完整加载链路图:一个都不能少

我们可以把整个加载过程画成一条线性依赖链:

Python 脚本 → PyQt5 (qsqlmysql.dll) → Qt 插件加载器 → 扫描 sqldrivers 目录 → 找到 qsqlmysql.dll → → 加载 qsqlmysql.dll → qsqlmysql.dll 尝试加载 libmysql.dll → → libmysql.dll 加载成功 → qsqlmysql.dll 初始化完成 → QSqlDatabase.open() 成功

只要其中任何一个环节断裂,最终呈现给用户的,都是同一个结果:Driver not loaded。而 Qt 并不会告诉你断在哪一环。所以,排查必须从最末端开始,逐级向上验证。

3. 四步精准排查法:从 DLL 存在性到运行时依赖的完整验证

面对Driver not loaded,网上充斥着“重装 PyQt5”、“重装 MySQL”、“把 dll 复制到 system32”等粗暴方案。这些方法偶尔奏效,但更多时候是碰运气,且无法复现、无法解释。下面是我总结的四步精准排查法,每一步都有明确的验证手段和预期结果,能帮你 100% 定位问题根源。

3.1 第一步:确认 qsqlmysql.dll 是否真实存在且路径正确

这是最基础也最容易被忽略的一步。很多人以为pip install PyQt5就自动配置好了所有驱动,其实不然。

操作步骤:

  1. 打开 Python 解释器,运行:

    from PyQt5.QtSql import QSqlDatabase import os print("PyQt5 Qt plugins path:", os.path.dirname(QSqlDatabase.__file__) + "/../../../Qt5/plugins")

    这会输出类似C:\Python39\Lib\site-packages\PyQt5\Qt5\plugins的路径。

  2. 进入该路径下的sqldrivers子目录(即C:\Python39\Lib\site-packages\PyQt5\Qt5\plugins\sqldrivers),检查是否存在qsqlmysql.dll文件。

  3. 如果不存在,说明你安装的 PyQt5 wheel不包含 MySQL 驱动。官方 pip wheel 从 5.15.0 开始,默认只包含qsqlite.dll和qsqlodbc.dll,MySQL 和 PostgreSQL 驱动需要额外安装。

解决方案:

  • 方案 A(推荐):安装PyQt5-tools,它通常会附带完整的驱动集:

    pip install PyQt5-tools

    安装后,qsqlmysql.dll会出现在PyQt5-tools\Qt\plugins\sqldrivers目录下,你需要手动复制到PyQt5\Qt5\plugins\sqldrivers。

  • 方案 B:使用 conda 安装,conda-forge 的 PyQt5 包默认包含所有驱动:

    conda install -c conda-forge pyqt
  • 方案 C:从 Qt 官网下载对应版本的 Qt MinGW 或 MSVC 安装包,提取qsqlmysql.dll。但要注意,Qt 官方库的qsqlmysql.dll是为 Qt Creator 编译的,可能与 PyQt5 的 ABI 不兼容,风险较高,不推荐新手尝试。

提示:不要试图从网上随便下载一个qsqlmysql.dll。不同 Qt 版本、不同编译器(MSVC vs MinGW)、不同架构(x64 vs x86)生成的 DLL 完全不兼容。我曾见过一个项目,开发者从 Qt 5.12 的安装包里拷贝了qsqlmysql.dll到 PyQt5 5.15 的目录下,结果程序启动时直接崩溃,因为 Qt 5.15 的QSqlDriver类内存布局已改变。

3.2 第二步:验证 qsqlmysql.dll 能否被 Qt 正确加载(排除路径和权限问题)

即使qsqlmysql.dll文件存在,Qt 也可能因权限或路径问题无法加载它。我们需要绕过 Python,用 Qt 自带的工具直接测试。

操作步骤:

  1. 下载并安装 Qt Creator (免费开源版即可)。
  2. 打开 Qt Creator,新建一个空的 Qt Widgets Application 项目。
  3. 在main.cpp的main()函数开头,添加以下代码:
    #include <QSqlDatabase> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication::addLibraryPath("C:/your/path/to/sqldrivers"); // 替换为你的 sqldrivers 目录绝对路径 qDebug() << "Available drivers:" << QSqlDatabase::drivers(); return 0; }
  4. 编译并运行该项目。观察输出窗口。

预期结果与分析:

  • 如果输出中包含"QMYSQL",说明qsqlmysql.dll路径正确,Qt 能成功加载它。问题一定出在libmysql.dll或其依赖上。
  • 如果输出是空列表[]或只有["QSQLITE", "QODBC"],说明 Qt 根本没找到qsqlmysql.dll。请检查:
    • addLibraryPath()中的路径是否拼写正确,是否是绝对路径。
    • sqldrivers目录下是否真的有qsqlmysql.dll(注意大小写,Windows 不敏感,但 Linux/macOS 敏感)。
    • 该目录是否有读取权限(尤其在企业域环境下,有时策略会限制访问)。

注意:QSqlDatabase::drivers()返回的是 Qt成功加载的驱动列表,不是磁盘上存在的文件列表。这是区分“文件存在”和“驱动可用”的黄金标准。

3.3 第三步:诊断 libmysql.dll 的加载状态(核心难点)

这是整个排查过程中最关键的一步,也是绝大多数人卡住的地方。我们需要确认qsqlmysql.dll是否能顺利加载libmysql.dll,以及libmysql.dll自身是否健康。

操作步骤(Windows):

  1. 下载 Process Monitor (微软官方免费工具)。
  2. 启动 Process Monitor,点击工具栏上的Filter → Filter...。
  3. 添加过滤规则:
    • Process Nameispython.exe(或你的 exe 文件名)
    • OperationisCreateFile
    • Pathcontainslibmysql
    • 点击Add,然后OK。
  4. 运行你的 Python 脚本(或打包后的 exe)。
  5. Process Monitor 会捕获所有CreateFile操作。在结果列表中,查找所有libmysql.dll的尝试记录。

关键观察点:

  • 查找Result列为NAME NOT FOUND的行。这表示 Qt 尝试在某个路径下寻找libmysql.dll,但没找到。记录下这些路径,它们就是 Qt 的搜索路径。
  • 查找Result列为SUCCESS的行。这表示libmysql.dll被找到了,但后续可能因依赖缺失而加载失败。
  • 查找Result列为PATH NOT FOUND或ACCESS DENIED的行。这表示路径本身不存在,或权限不足。

如果看到大量NAME NOT FOUND:说明libmysql.dll不在 Qt 的搜索路径中。你需要将libmysql.dll放到其中一个被搜索的路径下,最稳妥的是放到qsqlmysql.dll所在的sqldrivers目录里(同级),或者放到你的 Python 脚本/EXE 所在目录。

如果看到SUCCESS但程序仍报错:说明libmysql.dll被找到了,但它自身加载失败。这时需要用 Dependencies 工具打开libmysql.dll,查看其“Missing”依赖项。常见缺失项是VCRUNTIME140.dll、MSVCP140.dll、api-ms-win-crt-*.dll等。解决方案是安装 Microsoft Visual C++ 2015-2022 Redistributable 。

3.4 第四步:终极验证——用最小化 C++ 程序直连 MySQL

如果前三步都没发现问题,或者你想彻底排除 Python/PyQt5 层面的干扰,可以用一个极简的 C++ 程序来验证整个 MySQL 连接链路是否通畅。

创建test_mysql.cpp:

#include <QApplication> #include <QSqlDatabase> #include <QSqlError> #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("localhost"); db.setPort(3306); db.setDatabaseName("mysql"); // 连接 mysql 系统库做测试 db.setUserName("root"); db.setPassword("your_password"); if (db.open()) { qDebug() << "Success! Connected to MySQL."; qDebug() << "Driver version:" << db.driver()->metaObject()->className(); db.close(); } else { qDebug() << "Failed:" << db.lastError().text(); } return 0; }

编译与运行:

  • 如果你有 Qt Creator,新建一个 Qt Console Application,粘贴以上代码,编译运行。
  • 如果没有,可以使用qmake和mingw32-make(需安装 Qt MinGW 工具链)。

结果解读:

  • 如果 C++ 程序能成功连接,说明问题100% 出在你的 Python 环境或 PyQt5 安装上。可能是 Python 脚本路径、虚拟环境隔离、或 PyQt5 版本与 Qt 版本不匹配。
  • 如果 C++ 程序也报Driver not loaded,说明问题出在系统级的 Qt 插件或 MySQL 客户端库配置上,与 Python 无关。此时应重点检查PATH环境变量、libmysql.dll的位数匹配、以及 VC++ 运行库。

这四步法,每一步都提供了可量化的验证手段,避免了“我觉得应该没问题”的主观判断。我在客户现场处理过数十个同类案例,90% 的问题都能在第三步(Process Monitor)中定位到具体的libmysql.dll搜索路径缺失。

4. 生产环境部署方案:让驱动加载“永不掉链子”

开发机上跑通了,不代表生产环境也能跑通。用户电脑五花八门:有的装了多个 MySQL 版本,有的禁用了系统目录写入,有的用的是国产操作系统。我们必须设计一套鲁棒的部署方案,让qsqlmysql.dll和libmysql.dll的加载变得“傻瓜式”。

4.1 方案一:PyInstaller 打包时内嵌驱动(最推荐)

这是目前最成熟、最可控的方案。核心思想是:把所有依赖的 DLL 文件,和你的 Python 脚本一起打包进一个独立的 exe,让 Qt 的插件加载器永远能在./sqldrivers目录下找到它们。

操作步骤:

  1. 确保你的项目目录结构如下:

    myapp/ ├── main.py ├── sqldrivers/ # 手动创建的目录 │ ├── qsqlmysql.dll # 从 PyQt5 安装目录拷贝 │ └── libmysql.dll # 从 MySQL 安装目录拷贝(必须与 MySQL 服务器版本匹配) └── ...
  2. 使用 PyInstaller 打包时,显式指定--add-data参数:

    pyinstaller --onefile --add-data "sqldrivers;sqldrivers" main.py

    注意:--add-data的格式是"源路径;目标路径",Windows 下用分号;分隔,Linux/macOS 用冒号:。sqldrivers是目标路径,PyInstaller 会自动在生成的 exe 解压目录下创建sqldrivers子目录,并把源文件复制进去。

  3. 在main.py的开头,强制添加插件路径:

    import sys import os from PyQt5.QtWidgets import QApplication from PyQt5.QtSql import QSqlDatabase # 获取 exe 解压后的临时目录(PyInstaller 专用) if getattr(sys, 'frozen', False): # 打包后的 exe base_path = sys._MEIPASS else: # 直接运行 .py 文件 base_path = os.path.dirname(os.path.abspath(__file__)) # 将 sqldrivers 目录加入 Qt 插件搜索路径 plugin_path = os.path.join(base_path, 'sqldrivers') QApplication.addLibraryPath(plugin_path) # 现在再创建数据库连接 db = QSqlDatabase.addDatabase("QMYSQL") # ... rest of your code

优势:

  • 完全自包含,不依赖用户电脑上的任何环境变量或已安装软件。
  • qsqlmysql.dll和libmysql.dll的版本、位数、依赖关系由你完全掌控。
  • 用户双击 exe 即可运行,零配置。

注意事项:

  • libmysql.dll必须从你目标 MySQL 服务器版本的安装目录中提取。例如,你要连接 MySQL 8.0.33,就必须用 8.0.33 安装包里的libmysql.dll。
  • 如果你的应用需要连接不同版本的 MySQL(如同时支持 5.7 和 8.0),你需要在sqldrivers目录下放两个不同版本的libmysql.dll,并用代码逻辑在运行时切换。但这会极大增加复杂度,强烈建议统一后端 MySQL 版本。

4.2 方案二:环境变量注入法(适合企业内网统一部署)

如果你的软件是部署在公司内网,所有电脑都由 IT 部门统一管理,那么可以通过组策略或登录脚本,统一设置PATH环境变量,让libmysql.dll对所有进程可见。

操作步骤:

  1. 将libmysql.dll(以及VCRUNTIME140.dll等依赖)集中存放在一个网络共享目录,如\\server\mysql_libs\8.0.33\。
  2. 创建一个批处理脚本set_mysql_path.bat:
    @echo off setx PATH "%PATH%;\\server\mysql_libs\8.0.33" /M echo MySQL client library path added to system PATH. pause
  3. 通过域组策略,将此脚本设置为“计算机配置 → 策略 → Windows 设置 → 脚本(启动/关机)→ 启动”脚本。

优势:

  • 一次配置,全局生效,维护成本低。
  • libmysql.dll更新时,只需替换共享目录下的文件,所有客户端自动生效。

劣势:

  • 需要管理员权限,普通用户无法执行。
  • setx /M会修改系统级 PATH,可能与其他软件冲突。
  • 不适用于面向公众的独立软件分发。

4.3 方案三:运行时动态解压 DLL(高级技巧)

对于极致的便携性要求(如 U 盘绿色软件),可以将qsqlmysql.dll和libmysql.dll以二进制形式嵌入 Python 源码,程序启动时动态解压到临时目录,并设置QApplication.addLibraryPath()。

核心代码片段:

import tempfile import os import atexit from PyQt5.QtWidgets import QApplication # 嵌入的 DLL 数据(此处为示意,实际需用 base64 或其他方式编码) QSQLMYSQL_DLL_DATA = b'...' # 你的 qsqlmysql.dll 的二进制内容 LIBMYSQL_DLL_DATA = b'...' # 你的 libmysql.dll 的二进制内容 def setup_qt_plugins(): # 创建临时目录 temp_dir = tempfile.mkdtemp() # 解压 DLL 到临时目录 qsql_path = os.path.join(temp_dir, 'sqldrivers', 'qsqlmysql.dll') libmysql_path = os.path.join(temp_dir, 'sqldrivers', 'libmysql.dll') os.makedirs(os.path.dirname(qsql_path), exist_ok=True) with open(qsql_path, 'wb') as f: f.write(QSQLMYSQL_DLL_DATA) with open(libmysql_path, 'wb') as f: f.write(LIBMYSQL_DLL_DATA) # 注册插件路径 QApplication.addLibraryPath(temp_dir) # 程序退出时清理临时文件 def cleanup(): import shutil shutil.rmtree(temp_dir, ignore_errors=True) atexit.register(cleanup) # 在 QApplication 创建前调用 setup_qt_plugins() app = QApplication(sys.argv)

优势:

  • 真正的单文件分发,无需额外的 DLL 文件。
  • 完全规避了文件系统权限问题。

劣势:

  • 增加了源码体积和编译复杂度。
  • 每次启动都要解压,略微增加启动时间。
  • 需要处理 anti-virus 软件对临时文件的误报(部分杀软会拦截动态解压行为)。

无论选择哪种方案,核心原则不变:让qsqlmysql.dll和libmysql.dll的物理位置、版本、位数、依赖关系,全部处于你的掌控之中。不要寄希望于“用户电脑上恰好有”,那是运维噩梦的开始。

5. 避坑指南:那些让你多花三天却毫无收获的“伪解决方案”

在解决Driver not loaded的过程中,我见过太多开发者在错误的方向上狂奔。他们花了大量时间尝试各种“网上教程”,结果不仅没解决问题,还把原本正常的环境搞坏了。以下是几个最典型的“伪解决方案”,以及为什么它们是陷阱。

5.1 陷阱一:“重装 PyQt5 就能好”

这是最普遍的误区。很多人看到报错,第一反应就是pip uninstall PyQt5 && pip install PyQt5。但问题在于:pip install PyQt5安装的是一个 wheel 包,它包含了编译好的qsqlmysql.dll,但这个 DLL 的构建环境(编译器版本、Qt 版本、链接的libmysql.dll版本)是固定的。重装只是重新下载同一个 wheel,不会改变任何东西。

为什么无效?

  • 如果你原来装的就是PyQt5-5.15.19,重装后还是5.15.19,qsqlmysql.dll还是那个链接了 MySQL 5.7libmysql.dll的 DLL。
  • 如果你的 MySQL 是 8.0,问题依旧。
  • 更糟的是,重装可能覆盖掉你之前手动放置的qsqlmysql.dll,导致问题从“驱动加载失败”变成“驱动根本不存在”。

正确做法:

  • 先确认你用的是哪个 PyQt5 版本:pip show PyQt5。
  • 查看该版本的 wheel 是否包含 MySQL 驱动:去 PyPI 页面 ,下载对应的.whl文件,用7-Zip打开,检查PyQt5/Qt5/plugins/sqldrivers/目录下是否有qsqlmysql.dll。
  • 如果没有,不要重装,而是按上文“四步排查法”中的方案 A,安装PyQt5-tools并手动复制。

5.2 陷阱二:“把 libmysql.dll 复制到 C:\Windows\System32”

这是一个流传甚广的“土办法”。它的逻辑是:“System32 是系统目录,放这里肯定能找到”。但现代 Windows(Vista 及以后)引入了文件系统重定向(File System Redirector)和注册表重定向(Registry Redirector),使得 32 位程序在 64 位 Windows 上运行时,对System32的访问会被自动重定向到SysWOW64。

后果:

  • 你的 Python 是 64 位,libmysql.dll是 64 位,你把它复制到了C:\Windows\System32。
  • Qt 加载器在 64 位进程中搜索System32,找到了libmysql.dll,一切正常。
  • 但你的同事用的是 32 位 Python,他的 Qt 加载器在 32 位进程中搜索System32,结果被重定向到了C:\Windows\SysWOW64,而那里并没有libmysql.dll,于是报错。

更隐蔽的问题:

  • System32目录受 Windows Defender 和 UAC 保护,普通用户没有写入权限。强行复制可能导致权限错误。
  • 很多安全软件会监控System32的写入行为,将其视为恶意活动。

正确做法:

  • 永远不要往System32或SysWOW64里放第三方 DLL。
  • 把libmysql.dll放在你的应用目录下,或sqldrivers目录下,这是最干净、最可控的方式。

5.3 陷阱三:“用 pymysql 替代 QSqlDatabase”

有些开发者被Driver not loaded折磨太久,干脆放弃QSqlDatabase,转而用pymysql直接操作数据库,然后把查询结果手动塞进QTableView。这看似解决了问题,实则埋下了更大的隐患。

为什么是倒退?

  • QSqlDatabase是 Qt 的一部分,它提供了与QSqlTableModel、QSqlQueryModel、QSqlRelationalTableModel等模型的无缝集成。这些模型能自动处理排序、过滤、编辑、提交,极大简化 UI 层的数据绑定逻辑。
  • 用pymysql,你得自己写 CRUD 的 SQL 语句,自己处理事务,自己实现数据缓存和同步,自己处理并发修改冲突。工作量呈指数级增长。
  • QSqlDatabase支持异步查询(QSqlQuery::exec()是同步的,但你可以用QThread封装),而pymysql的阻塞式 IO 会让 UI 卡死,除非你手动做线程管理。

正确思路:

  • Driver not loaded是一个环境配置问题,不是架构问题。
  • 花一天时间彻底解决它,换来的是未来几个月的开发效率提升。
  • 如果实在无法解决,那说明你的技术选型有问题——要么换用 SQLite(QSQLITE驱动是内置的,永不报错),要么换用PySide6(它对 MySQL 驱动的支持更友好,且社区活跃度更高)。

5.4 陷阱四:“升级到 PyQt6 或 PySide6 就一劳永逸”

PyQt6 和 PySide6 确实在驱动管理上做了改进,比如支持更灵活的插件路径、更好的错误提示。但升级本身就是一个巨大的工程。

现实挑战:

  • PyQt5 和 PyQt6 的 API 有显著差异:QApplication.exec_()变成了QApplication.exec(),QFileDialog.getOpenFileName()的返回值元组结构变了,QPainter的绘图 API 也有调整。
  • 如果你的项目有几万行代码,升级不是改几个 import 语句那么简单,而是一场全面
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 1:03:56

森林害虫YOLO目标检测数据集:松毛虫/松墨天牛/卷叶蛾实采标注

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:03:52

DBSCAN实时超像素分割:工业检测60fps落地实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:03:37

STM32G431 GPIO底层原理与蓝桥杯实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:03:06

SystemVerilog对象拷贝与参数化类:验证环境实战陷阱解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:01:57

PBD物理模拟实战:位置驱动、约束求解与工业级优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:01:55

LeGO-LOAM地面分离原理与工业级代码实现解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华