1、类声明:
#pragma once
#include <mysql.h>
#include <stdlib.h>
#include <stdio.h>
// 与数据库交互的工具类
class DBUtil {
public:
// 默认构造
DBUtil();
// 移动构造
DBUtil(DBUtil&& rv) noexcept;
// 移动赋值
DBUtil& operator=(DBUtil&& rv) noexcept;
// 析构函数
~DBUtil();
// 连接数据库
// 主机ip地址、用户名、密码、数据库名、端口
// 成功返回0
// 失败返回-1
int Connect(const char* host, const char* user, const char* passwd, const char* dbName, int port = 3306);
// 断开连接
void Disconnect();
// 执行SQL语句
// 成功返回0
// 失败返回-1
int SQL(const char* sql);
// 获取结果集中表头信息
// 失败返回空指针
// MYSQL_FIELD(字段信息结构体)eg:
// char *name 字段名
// char *table 所属表名
// enum enum_field_tyoes type 类型
// unsigned int length 子段宽度
// unsigned int flags 约束/属性
MYSQL_FIELD* Desc();
// 获取结果集的列数
size_t Cols();
// 获取结果集的行数
size_t Rows();
// 返回上一次操作影响的条目数,针对DML语句
size_t AffectItems();
// 下一行查询结果
// 空指针结束
char** Next();
// 打印结果集信息
// 成功返回0
// 失败返回-1
int Print();
private:
// 初始化函数,申请基本资源
void Init();
protected:
// 数据库操作句柄
MYSQL* mql;
// 查询的结果集
MYSQL_RES* res;
};
2、类实现:
DBUtil::DBUtil() :mql(nullptr), res(nullptr) { }
DBUtil::DBUtil(DBUtil&& rv) noexcept :mql(rv.mql), res(rv.res) {
rv.mql = nullptr;
rv.res = nullptr;
}
DBUtil& DBUtil::operator=(DBUtil&& rv) noexcept {
this->mql = rv.mql;
this->res = rv.res;
rv.mql = nullptr;
rv.res = nullptr;
return *this;
}
DBUtil::~DBUtil() {
if (this->res) mysql_free_result(this->res);
if (this->mql) mysql_close(this->mql);
}
void DBUtil::Init() {
mql = new MYSQL;
}
int DBUtil::Connect(const char* host, const char* user, const char* passwd, const char* dbName, int port) {
this->Init();
// 初始化操作句柄
// PS:如果传入一个空指针,将返回一个自动分配的操作句柄(不建议这么做,在析构时可能出现问题)
mysql_init(this->mql);
// 连接数据库函数
// 成功返回操作句柄
// 失败返回空指针
// 后两个参数设置为空和0即可
// 详细可参考:https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-connect.html
if (!mysql_real_connect(this->mql, host, user, passwd, dbName, port, nullptr, 0)) {
// 检错函数
printf("%s\n", mysql_error(this->mql));
return -1;
}
// 执行sql语句
// 失败返回非0
// SET NAMES GBK:设置编码格式,否则cmd下中文乱码
if (mysql_query(this->mql, "set names gbk")) {
printf("%s\n", mysql_error(this->mql));
return -1;
}
return 0;
}
// 断开连接
void DBUtil::Disconnect() {
if (this->res) {
mysql_free_result(this->res);
this->res = nullptr;
}
if (this->mql) {
mysql_close(this->mql);
this->mql = nullptr;
}
}
int DBUtil::SQL(const char* sql) {
if (!this->mql) {
puts("Not connect database");
return -1;
}
if (mysql_query(this->mql, sql)) {
printf("%s\n", mysql_error(this->mql));
return -1;
}
// 释放之前结果集所占内存
if (this->res) {
mysql_free_result(this->res);
this->res = nullptr;
}
// 获取结果集
// 失败返回空指针
this->res = mysql_store_result(this->mql);
// 如果结果集为空,列数为零说明可能执行了DML语句
// 如果结果集为空,列数不为零说出现异常(内存分配失败等)
if (!res && mysql_field_count(this->mql)) {
printf("%s\n", mysql_error(this->mql));
return -1;
}
return 0;
}
MYSQL_FIELD* DBUtil::Desc() { return this->res ? mysql_fetch_fields(this->res) : nullptr; }
size_t DBUtil::Cols() { return this->res ? mysql_num_fields(this->res) : 0; }
size_t DBUtil::Rows() { return this->res ? mysql_num_rows(this->res) : 0; }
size_t DBUtil::AffectItems() { return mysql_affected_rows(this->mql); }
char** DBUtil::Next() { return this->res ? mysql_fetch_row(this->res) : nullptr; }
int DBUtil::Print() {
if (!this->res) return puts("empty set"), -1;
MYSQL_FIELD* fd = this->Desc();
if (!fd) return printf("%s\n", mysql_error(this->mql)), -1;
size_t col = this->Cols();
for (size_t i = 0; i < col; i++) printf("%s ", fd[i].name);
puts("");
// 每行数据
char** data;
// 获取下一行信息
while (data = this->Next()) {
for (size_t i = 0; i < col; i++) printf("%s ", data[i]);
puts("");
}
return 0;
}