在项目开发过程中,如果涉及到数据的存储,那么肯定会用到数据库。常用的关系型数据库(操作的时候需要使用sql语句)有:mysqloraclesqllite等。在Qt框架中也同样提供了对这些数据库的支持,我们使用Qt提供的数据库类就可以在上层使用相同的接口对各种数据库进行操作了,非常的nice。

关于在程序中连接数据库有很多种处理方式,比如:odbcado等,在Qt底层也对数据库的连接进行了封装,基于不同的连接方式为我们提供了不同的插件(二进制代码,在需要的时候被加载,表现形式为动态库、静态库)。虽然如此,但是有一点很杯具:在高版本的Qt中官方并没有为我们提供可用的mysqloralce插件,只提供了源代码(不能直接使用),需要我们基于这些源码自行编译得到对应的动态库(静态库)之后,才能被程序加载从而连接上相应的数据库。

由于mysql是我们日常工作和学习中用的最多的一种数据库,所以下面为大家讲解一下如何在 Qt 中编译出可用的 MySql 插件。

本文演示使用的版本说明:

  1. 使用的IDE:QtCreator

  2. Qt 版本:5.15.2

  3. 数据库版本:MySql 8.0.27 - 64bit

  4. 使用的编译套件:MinGW - 64bit 或者 MSVC- 64bit


关注微信公众号爱编程的大丙,回复827 无需翻墙直接下载MySQL安装包。


在继续向下阅读本文之前,需要保证本地的Qt环境已经配置好了,如果不知如何操作,请参考Qt环境变量的配置

1. 版本的选择

在编译MySql插件之前,需要先确认一下我们本地使用的 Qt 以及 MySql 版本,这一点非常重要,主要需要考虑以下两个维度:

1.1 Qt 和数据库的版本

场景1

低版本的 Qt + 低版本的数据库

  • 关于 Qt 的版本本人没有挨个版本依次印证,用过的 5.9.3 版本及以前是有 MySql 数据库插件的。
  • 低版本的数据库指的是 5.6.x 以及 5.7.x 版本

场景2

低版本的 Qt + 高版本的数据库

  • 关于 Qt 的版本本人没有挨个版本依次印证,用过的 5.9.3 版本及以前是有 MySql 数据库插件的。
  • 高版本的数据库指的是 8.0 及以上版本(截稿之前最新版本是 8.0.27)

场景3

高版本的 Qt + 低版本的数据库

  • 此处高版本的 Qt 指的是 5.9.3+ 以上的版本(不包括Qt6相关版本)
  • 低版本的数据库指的是 5.6.x 以及 5.7.x 版本

场景4

高版本的 Qt + 高版本的数据库

  • 此处高版本的 Qt 指的是 5.9.3+ 以上的版本(不包括Qt6相关版本)
  • 高版本的数据库指的是 8.0 及以上版本(截稿之前最新版本是 8.0.27)

场景5

Qt6 相关版本 + 数据库

在Qt6中编译插件使用的 cmake,本文内容不适用于该场景。

1.2 Qt 编译套件和数据库的位数

此处需要强调一点,重要的事情说三遍:

  1. Qt 编译套件的位数和数据库的位数必须相同,都是32位或都是64位。
  2. Qt 编译套件的位数和数据库的位数必须相同,都是32位或都是64位。
  3. Qt 编译套件的位数和数据库的位数必须相同,都是32位或都是64位。

如果不能满足上述描述的情况,那么在编译 MySql 插件的时候必然是失败的。

2. 准备工作

我们在 Qt 中编译 MySql 插件的时候需要用到 MySql 的动态库和头文件,所以需要提前把这些需要的库文件准备出来,一共有两种方式:

  • 官方下载安装版的 MySql,可以在安装目录中找到库文件和头文件
  • 官方下载绿色版的 MySql,可以在解压目录中得到需要的库文件和头文件

MySQL官方地址(有时候好像需要架梯子才能访问):

1
https://dev.mysql.com/downloads/

image-20211212173219647

建议安装绿色版,比较省事儿。

2.1 安装版 MySql

下载

去MySQL官方下载最新版的mysql,地址如下:

1
https://dev.mysql.com/downloads/installer/

image-20211212174437924

目前的最新版本是8.0.27,将安装包下载到本地,直接安装即可。

安装

安装 MySql 第一步,建议选择自定义安装,这样就可以选择安装的版本和设置安装路径了。

在向导的第一步,选择自定义安装。

image-20211126180740565

在向导的第二步需要选择安装的版本,官方一共提供了三个稳定版本:8.05.75.6,这里我们选择安装最新版本。

image-20211126181152813

通过截图可以看出,在8.0版本中没有提供32位版本,只有64位版本。在选择版本的时候此处一定要注意一个细节:

  1. 此处安装的mysql版本位数需要和自己使用的Qt的编译套件的位数一致(都是32位或者都是64位。这是第四遍强调这个问题了哦~~~)。
  2. 如果Qt的编译套件版本为32位可以选择安装较低版本的mysql,在另外两个版本中都提供了32位的安装包。
  3. mysql的5.6或者5.7依然是现在大家使用的主流版本。

image-20211126182030529

选择好要安装的版本之后,接下来需要设置一下mysql的安装目录,此处有第二个细节需要注意:

mysql的安装目录的目录名中建议不要包含空格【类似于这种:Program Files (x86)】,否则在编译 Qt 需要的 mysql 插件的时候会比较麻烦。

image-20211126182615279

修改完mysql的安装目录之后(目录名多个单词之间建议不要有空格),就可以进行下一步的安装了。

image-20211126182924422

接下来的几步,直接Next就可以了。

image-20211126183046629

该窗口设置无需修改,记住mysql数据库使用的默认通信端口是3306就可以了,后边几步还是默认Next无需设置。

image-20211126183308990

在这个向导窗口需要设置mysql数据库密码,在连接数据库的时候需要使用这个密码,后边几步还是默认Next无需修改。

image-20211126183424162

点击窗口中的Execute安装开始安装数据库。

image-20211126183605254

到此为止,安装结束,剩余几步按照向导提示进行操作就可以了。

安装成功之后的本地目录中的内容,如下图:

image-20211212175840465

2.2 绿色版 MySql

下载地址:

1
https://dev.mysql.com/downloads/mysql/

image-20211212175524095

将下载得到的压缩包解压到本地目录中(自己指定即可),可以看到如下内容:

image-20211212205342834

通过对比可以看到,安装版和绿色版的 MySql 目录结构是一样的(内容其实也一样)。

2.3 准备 Qt 源码

如果想要自己能够编译出 MySql 插件,需要有一个前提条件就是在安装 Qt 的时候安装了相关的源码,如果没有安装可以通过 Qt 提供的在线工具进行添加:

image-20211126184312603

image-20211126184516813

  • 此工具是 Qt 自动的,无需额外安装
  • 高版本 Qt 可以直接使用,低版本需要升级或官网下载新版本。

准备工作完成之后,我们就可以去找自己本地的Qt源码目录了,以我为例,Qt是安装到了C盘的Qt目录下。

image-20211126184859873

到此为止,准备工作完成。

3. 编译 mysql 插件

3.1 打开项目文件

根据上面的描述,我们已经找到了 Qt 的源码目录,打开编译 mysql 插件的项目文件,我本地的具体路径如下(路径的后边部分都是相同的):C:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers\mysql

image-20211126185156202

第一次打开项目需要选择编译套件,根据自身情况选择下面其中一种即可:

使用MinGW编译套件

image-20211126185447040

使用MSVC编译套件

image-20211215211403477

在使用QtCreator配置这个项目是时候有一个细节需要注意:

这是第五次强调这个问题了哦 ~ ~ ~

  1. 如果本地的mysql是32位版本,选择的Qt编译套件应该是32位
  2. 如果本地的mysql是64位版本,选择的Qt编译套件应该是64位
  3. 如果没有遵守以上规则,无法编译出需要的mysql驱动

3.2 修改项目文件

项目打开之后,修改项目文件mysql.pro

image-20211126190139558

  • LIBS:指定的本地mysql动态库路径和动态库的名字

    • -L:指定库的路径
    • -l指定库的名字,不需要写后缀,对应的文件全名为libmysql.dll

    我本地的mysql安装目录是这样滴:

    image-20211126190649355

  • INCLUDEPATHDEPENDPATH:指定的是本地mysql的头文件目录

    image-20211212213450837

3.3 修改错误信息

配置完毕之后, 就可以编译该项目了。

image-20211126190953062

在编译输出窗口中可以看到有一条警告信息:Cannot read C:/qtsqldrivers-config.pri: No such file or directory这个提示是说没找到那个文件,其实这个文件确实也是不存在的,因此需要修改一下,我们首先需要打开项目中的这个qsqldriverbase.pri文件:

image-20211212211214379

打开qsqldriverbase.pri文件所在目录(通过右键菜单打开文件目录)

image-20211212211602893

可以看到它和configure.pri在同一个目录中:

image-20211212211419772

修改完毕之后在编译,项目就没有错误了。编译成功(注意是编译而不是运行)之后,我们就得到了该项目生成的库文件,库文件的位置在安装 Qt 所在盘符的plugins目录中(比如我的Qt装到了C盘,那么这个plugins目录就需要去C盘下去找,它会自动生成)。

使用MinGW编译套件

image-20211126191614760

使用MSVC编译套件

image-20211215212206066

  • qsqlmysql.dll :Release 版本的动态库
  • qsqlmysqld.dll :Debug 版本的动态库

可以看到,在这个目录下生成了动态库和静态库,这就是Qt连接MySQL的时候需要的插件(默认情况下程序是动态链接的方式加载库文件,所以需要的是动态库),我们要做的事情是需要把生成的这几个文件拷贝到Qt编译套件对应的目录下(需要先找到Qt的安装目录),对于我本地而言是这个目录:

使用MinGW编译套件

  • 本地示例目录:C:\Qt\5.15.2\mingw81_64\plugins\sqldrivers

image-20211126194040699

使用MSVC编译套件

  • 本地示例目录:C:\Qt\5.15.2\msvc2019_64\plugins\sqldrivers

image-20211215212701383

在拷贝的时候需要注意一个细节:

这是第六次强调这个问题了哦 ~ ~ ~

在编译 mysql 驱动的时候使用的Qt 64位的编译套件,因此需要把生成的库文件拷贝到 64 位编译套件对应的目录中(也就是 mingw版本号_64 目录)。

另外,还需要将 MySQL 的动态库拷贝到 Qt 的编译套件目录中,先找到MySQL的动态库:

image-20211126201406671

再找到 Qt 的编译套件目录(这里需要找64位的编译套件目录),对于我本地电脑而言,该目录路径为:

使用MinGW编译套件

  • 本地示例目录:C:\Qt\5.15.2\mingw81_64\bin

image-20211126201555346

使用MSVC编译套件

  • 本地示例目录:C:\Qt\5.15.2\msvc2019_64\bin

image-20211215213250609

4. 连接数据库

4.1 连接 MySQL 的代码

项目文件 .pro

1
2
# 在项目文件中添加数据库模块 sql
QT += core gui sql

源文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <QSqlDatabase>
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlError>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

QStringList list = QSqlDatabase::drivers();
qDebug() << list;

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
if(db.isValid())
{
QMessageBox::information(this, "conn", "ok");
}
else
{
QMessageBox::information(this, "conn", "error");
}
db.setHostName("127.0.0.1"); // 本地连接
db.setPort(3306); // 如果使用的是默认端口可以不设置
db.setUserName("root"); // 数据库用户名
db.setPassword("root"); // 数据库密码
db.setDatabaseName("mysql"); // 数据库名字
if(db.open())
{
QMessageBox::information(this, "打开数据库", "数据库打开成功, 可以读写数据了......");
}
else
{
QString msg = "数据库打开失败: " + db.lastError().text();
QMessageBox::information(this, "打开数据库", msg);
}
}

在执行上述测试代码的时候,要求满足一下几个条件:

  1. 测试者本地或者远程服务器上已经部署了 MySQL
  2. 如果是连接 Linux 远程 MySQL 服务器,需要确认已经开放了连接权限
  3. 确认 MySQL 的端口,默认是 3306
  4. 确认数据库的连接用户名和密码
    • 用户名默认是 root,密码是自己设置的
  5. 对于 MYSQL 数据库而言,一个用户名下有多个数据库,示例程序中的 mysql 是一个自带的数据库,也可以连接自己创建的数据库。

在上面的程序中执行这样两句代码:

1
2
QStringList list = QSqlDatabase::drivers();
qDebug() << list;

程序执行打印的信息如下:

1
("QSQLITE", "QMARIADB", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7")

其中有一个字符串叫做 QMYSQL 这是连接 MySql 数据库需要的驱动的名字,如果能够检测到 MySQL 插件就能看到这个字符串,如果没有按照前面的步骤编译出这个插件放到指定目录,则看不到这个驱动名,自然也无法连接 MySql 数据库。

4.2 遇到的问题

MySql 8.0 之前的版本

对于 MySql 8.0 之前的版本,做到这一步就结束了,可以成功连接到 MySql 数据库,大功告成。

MySql 8.0 及之后的版本

对于MySql 8.0 之后的版本,提高了客户端和服务器数据通信的安全性,也就是说对通信数据做了加密,所以还需要依赖一些其他的动态库,否则程序是无法运行的,会提示驱动无法被加载,提示信息如下:

1
QSqlDatabase: QMYSQL driver not loaded

或者

image-20211214111613758

4.3 解决方案

关于上述问题的原因已经给大家介绍清楚了,就是缺少安全模块的动态库,其实这个库文件就是 openssl 的动态库,我们无需自己安装,官方是有提供的。首先打开官网下载地址:

1
https://dev.mysql.com/downloads/

image-20211214131136279

下载使用C++连接数据库需要的组件(建议下载和本地 mysql 动态库一致的版本):

image-20211214133050489

可以根据自己的实际需求选择安装版或者绿色版以及32bit或64bit。安装或解压完毕之后,我们就可以得到这样一个目录:

image-20211214131802866

进入到lib64目录:

image-20211214131921902

目录中的libcrypto-1_1-x64.dlllibssl-1_1-x64.dll就是我们需要的动态库,把这两个动态库拷贝到和连接数据库的可执行程序同一级目录中就可以了。

使用MinGW编译套件

  1. 直接启动可执行程序连接数据库

    找到测试程序对应的build目录,在进入到可执行程序所在的debug或者release目录,把上面找到的两个动态库拷贝到这里就可以了。

image-20211214132615637

  1. 在QtCreator中启动程序连接数据库

    如果是通过QtCreator启动可执行程序测试数据库的连接,那么这两个动态库需要放到build中,而不是和可执行程序放到一起,这一点我们必须要了解。

image-20211214133400836

使用MSVC编译套件

如果使用的是 VS 的编译套件,我们只需要把两个动态库拷贝到项目的build目录下就可以了(这个比较省事儿)。

image-20211215214350321

按照上述步骤操作完毕之后,我们就可以成功连接MySQL数据库了

image-20211214133503383

happy