C++ 使用 API 连接 MySQL 数据库

前言

本文将介绍 C++ 如何使用 MySQL Connector/C++ 的 API 连接 MySQL 数据库,适用于 Windows 系统。

版本说明

软件版本默认安装路径
MySQL Connector/C++1.1.13C:\Program Files\MySQL\MySQL Connector C++ 1.1.13
OpenSSLv1.1.1LC:\Program Files\OpenSSL-Win64
boost1_77_0C:\Program Files\boost_1_77_0
MySQL Server5.7.33
C++11
Visual Studio2019
Windows SystemWin 10

MySQL Connector/C++ 介绍

简介

MySQL Connector/C++ 是一个 MySQL 数据库连接器,包含了 C++ 连接 MySQL 服务器所需的头文件和库文件,可用于开发基于 JDBC 的 C++ 应用程序。

开发优势

与 MySQL 客户端库提供的 C 语言 API 相比,MySQL Connector/C++ 为 C++ 用户提供以下好处:

  • 纯 C++ 开发的便利
  • 支持基于 JDBC 4.0 的 API
  • 支持面向对象的编程范式
  • 减少项目的开发时间
  • 可根据要求获得商业许可证
  • 根据 GPL 获得许可,但 FLOSS 许可除外

分发方式

MySQL Connector/C++ 有二进制文件和源代码分发版,并以特定于平台的打包格式提供:

  • 二进制分发版可用于 Windows、Linux、Unix 和类 Unix 平台
  • 源代码分发版可作为压缩的 tar 文件或 zip 文件提供,并可在任何受支持的平台上使用
  • 源代码存储库使用 Git 存储,可在 GitHub 上获得

与 JDBC 的兼容性

MySQL Connector/C++ 与 JDBC 4.0 API 兼容,没有实现整个 JDBC 4.0 API,但具有以下类:Connection、DatabaseMetaData、Driver、PreparedStatement、ResultSet、ResultSetMetaData、Savepoint、Statement。JDBC 4.0 API 为刚才提到的类定义了大约 450 个方法,MySQL Connector/C++ 实现了其中的大约 80%。

支持的平台和先决条件

对于 MySQL Connector/C++ 1.1.11 及更高版本,商业和社区发行版需要依赖 Visual C++ Redistributable for Visual Studio 2015 才能在 Windows 平台上运行。从 MySQL Connector/C++ 1.1.10 开始,社区(非商业)发行版需要依赖适用于 Visual Studio 2013 的 Visual C++ Redistributable。可在 Microsoft 下载中心获取 Redistributable 的安装包,并在安装 MySQL Connector/C++ 之前安装它。

  • 要运行带 MySQL Connector/C++ 的应用程序,需要 MySQL 5.6 或更高版本的数据库服务器

  • 要构建带 MySQL Connector/C++ 的应用程序

    • 在 Windows 系统上,需要 Microsoft Visual Studio 2015
  • 要从源代码构建 MySQL Connector/C++ 自身

    • 在 Windows 系统上,需要 Microsoft Visual Studio 2015
    • Building Connector/C++ 需要 MySQL 5.7(5.7.9 或更高版本)或 MySQL 8.0(8.0.11 或更高版本)的客户端库

准备工作

OpenSSL 安装

安装 OpenSSL

OpenSSL 官网 下载 Win64 OpenSSL v1.1.1L 版本的安装包,下载完成后直接安装,每一步安装步骤选择默认选项即可。OpenSSL 默认的安装路径是 C:\Program Files\OpenSSL-Win64

VS 项目添加 OpenSSL 的 库文件

OpenSSL 安装完成之后,将其安装目录下的 bin 文件夹中的 libssl-1_1-x64.dlllibcrypto-1_1-x64.dll 库文件拷贝到 VS 项目的目录中,如下图所示:

VS 项目引入 OpenSSL 的 头文件

右键项目,选择 属性,导航到 配置属性 -> C/C++ -> 常规 -> 附加包含目录,添加 OpenSSL 头文件所在的目录路径(如 C:\Program Files\OpenSSL-Win64\include),如下图所示:

MySQL Connector/C++ 安装

安装 MySQL Connector/C++

MySQL 官网 上下载 1.1.13 版本的 MySQL Connector/C++,下载完成后直接安装即可。若已经本地已经安装过 MySQL Server,则不再需要手动安装 MySQL Connector/C++,因为默认已经安装过了,但需要留意 MySQL Connector/C++ 与 MySQL 的版本是否匹配 。值得一提的是,MySQL Connector/C++ 支持多个版本共存(同时安装不同的版本),其默认的安装路径为 C:\Program Files\MySQL\Connector.C++ 1.x

VS 项目添加 MySQL Connector/C++ 的 库文件

MySQL Connector/C++ 安装完成后,将其安装目录下 lib/opt 文件夹中的 mysqlcppconn.dllmysqlcppconn.lib 库文件拷贝到 VS 项目的目录中,如下图所示:

VS 项目引入 MySQL Connector/C++ 的头文件

右键项目,选择 属性,导航到 配置属性 -> C/C++ -> 常规 -> 附加包含目录,添加 MySQL Connector/C++ 头文件所在的目录路径(如 C:\Program Files\MySQL\MySQL Connector C++ 1.1.13\include),如下图所示:

C++ 连接 MySQL 的实战案例

MySQL 数据库初始化

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
-- ----------------------------
-- 创建数据库
-- ----------------------------
DROP DATABASE IF EXISTS `t_shop`;
CREATE DATABASE `t_shop` DEFAULT CHARACTER SET UTF8;

-- ----------------------------
-- 切换数据库
-- ----------------------------
USE `t_shop`;

-- ----------------------------
-- 创建数据库表
-- ----------------------------
DROP TABLE IF EXISTS `properties`;
CREATE TABLE `properties` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`KEY` varchar(200) DEFAULT NULL,
`VALUE` varchar(200) DEFAULT NULL,
`REMARK` varchar(200) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `key_unique_index` (`KEY`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=UTF8 ROW_FORMAT=DYNAMIC;

-- ----------------------------
-- 往数据库表插入数据
-- ----------------------------
INSERT INTO `properties` (`KEY`, `VALUE`, `REMARK`) VALUES ('test_limit_price', '30.5', '限制价格');
INSERT INTO `properties` (`KEY`, `VALUE`, `REMARK`) VALUES ('test_limit_number', '430', '限制数量');
INSERT INTO `properties` (`KEY`, `VALUE`, `REMARK`) VALUES ('test_limit_balance', '929.32', '限制余额');

C++ 连接 MySQL 的代码

  • mysqldb.h
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
#pragma once

#include <vector>
#include <iostream>
#include <mysql_connection.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>

using namespace std;
using namespace sql;

// MySQL数据库操作类
class MysqlDB {

public:
MysqlDB(const string host, const string username, const string password, const string database);
~MysqlDB();

public:
bool Execute(const char* sql);
int ExecuteUpdate(const char* sql);
unique_ptr<ResultSet> Query(const char* query, const vector<string> parameters);

private:
string host;
string username;
string password;
string database;
Driver* driver;
unique_ptr<Connection> connection; // 智能指针
};
  • mysqldb.cpp
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "mysqldb.h"

// 构造函数
MysqlDB::MysqlDB(const string host, const string username, const string password, const string database) {

// 初始化MySQL的连接信息
this->host = host;
this->username = username;
this->password = password;
this->database = database;

try {
// 加载MySQL驱动
this->driver = get_driver_instance();
if (!this->driver) {
throw "failed to load mysql driver";
}

// 连接MySQL实例
this->connection.reset(driver->connect(this->host.c_str(), this->username.c_str(), this->password.c_str()));
if (!this->connection) {
throw "failed to connect mysql server";
}
else {
// 设置默认数据库
this->connection->setSchema(this->database.c_str());
}
}
catch (SQLException& e) {
cout << "# ERR: SQLException in " << __FILE__ << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what() << endl;
};
}

// 析构函数
MysqlDB::~MysqlDB() {

}

// 用于执行任何 SQL 语句,返回一个 bool 值,表明执行该 SQL 语句是否返回了 ResultSet
// 如果执行后第一个结果是 ResultSet,则返回 true,否则返回 false
bool MysqlDB::Execute(const char* sql) {
try {
if (this->connection) {
unique_ptr<Statement> statement = nullptr;
statement.reset(this->connection->createStatement());
if (statement)
{
return statement->execute(sql);
}
}
}
catch (SQLException& e) {
cout << "# ERR: SQLException in " << __FILE__ << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what() << endl;
}
return false;
}

// 用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE
// 函数的返回值是一个整数,指示受影响的行数,对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,返回值总为零
int MysqlDB::ExecuteUpdate(const char* sql) {
try {
if (this->connection) {
unique_ptr<Statement> statement = nullptr;
statement.reset(this->connection->createStatement());
if (statement)
{
return statement->executeUpdate(sql);
}
}
}
catch (SQLException& e) {
cout << "# ERR: SQLException in " << __FILE__ << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what() << endl;
}
return 0;
}

// 基于 SQL 的预编译机制,执行查询单个结果集(ResultSet)的 SQL 语句,例如 SELECT 语句
unique_ptr<ResultSet> MysqlDB::Query(const char* sql, const vector<string> parameters) {
unique_ptr<ResultSet> resultSet = nullptr;
try {
if (this->connection) {
int index = 0;
unique_ptr<PreparedStatement> statement = nullptr;
statement.reset(this->connection->prepareStatement(sql));
if (statement) {
for (auto iterator = parameters.cbegin(); iterator != parameters.cend(); iterator++) {
index++;
statement->setString(index, (*iterator).c_str());
}
resultSet.reset(statement->executeQuery());
}
}
}
catch (SQLException& e) {
cout << "# ERR: SQLException in " << __FILE__ << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what() << endl;
}
return resultSet;
}
  • main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include "mysqldb.h"

using namespace std;

int main() {
unique_ptr<MysqlDB> db(new MysqlDB("tcp://127.0.0.1:3306", "root", "123456", "t_shop"));

string querySql = "select * from properties where `KEY` = ?";
unique_ptr<ResultSet> result = db->Query(querySql.c_str(), { "test_limit_price" });
if (result) {
cout << "Query: " << querySql << endl;
while (result->next()) {
cout << result->getInt("ID") << " | ";
cout << result->getString("KEY").c_str() << " | ";
cout << result->getString("VALUE").c_str() << " | ";
cout << result->getString("REMARK").c_str() << " | ";
cout << endl;
}
}
return 0;
}

程序运行输出的结果如下:

1
2
Query: select * from properties where `KEY` = ?
27 | test_limit_price | 30.5 | 限制价格 |

常见问题

缺失 Boost 库

错误信息:

  • 项目执行编译操作后,VS 出现下述错误信息,这是本地缺失 boost 库导致的。
    1
    fatal error C1083: 无法打开包括文件: “boost/shared_ptr.hpp”: No such file or directory

解决方法:

  • a) 在 Boost 官网 下载最新版本的 Boost,并解压到本地磁盘,例如解压路径为:C:\Program Files\boost_1_77_0
  • b) 右键项目,选择 属性,导航到 配置属性 -> C/C++ -> 常规 -> 附加包含目录,添加 Boost 的安装路径(如 C:\Program Files\boost_1_77_0),如下图所示
  • c) 重新执行项目的编译操作

缺失 libssl-1_1-64.dll 文件

错误信息:

  • 项目运行后,系统弹窗提示以下错误信息。
    1
    由于找不到 libssl-1_1-64.dll,无法继续执行代码。重新安装程序可能会解决此问题。

解决方法:

  • 安装 OpenSSL,并拷贝 libssl-1_1-64.dll 库文件到 VS 项目的目录中,具体步骤可参考上面的 OpenSSL - 安装 教程。

缺失 libcrypto-1_1-x64.dll 文件

错误信息:

  • 项目运行后,系统弹窗提示以下错误信息。
    1
    由于找不到 libcrypto-1_1-x64.dll,无法继续执行代码。重新安装程序可能会解决此问题。

解决方法:

  • 安装 OpenSSL,并拷贝 libcrypto-1_1-x64.dll 库文件到 VS 项目的目录中,具体步骤可参考上面的 OpenSSL - 安装 教程。

参考文档