摘要
本篇文章主要介绍通过C语言API接口链接MySQL数据库,各接口功能及使用方式,辅助类的封装及调用实例,可以直接移植到项目里面使用。
目录
1、环境配置
1.1、添加头文件
1.2、添加库目录
2、接口介绍
2.1、MySql初始化及数据清理
2.1.1、mysql_ibrary_init 接囗说明
2.1.2、mysql_library_end 接囗说明
2.1.3、mysql_init 接口说明
2.1.4、mysql_close 接口说明
2.2、MySql 数据库链接
2.2.1、mysql_real_connect 接囗说明
2.2.2、mysql_options接口说明
2.3、数据库查询
2.3.1、mysql_real_query接囗说明
2.3.2、mysql_affected_rows接囗说明
2.3.3、mysql_error接囗说明
2.3.4、mysql_use_result接囗说明
2.3.5、mysql_store_result 接囗说明
2.3.6、mysql_fetch_field 接囗说明
2.3.7、mysql_num_felds 接囗说明
2.3.8、mysql_fetch_row接囗说明
2.3.9、mysql_fetch_lengths 接囗说明
2.3.10、mysql_fetch_field_direct 接囗说明
2.3.11、mysql_free_result 接囗说明
2.4、使用实例
3、全网最全辅助类实现
3.1、MySqlHelper.h
3.2、MysqlHelper.cpp
3.3、调用实例
1、环境配置
1.1、添加头文件
打开项目属性页面,在C/C++->常规->附加包含目录中添加“D:\MySQL\mysql-8.0.37-winx64\include”目录。
1.2、添加库目录
打开项目属性页面,在连接器>常规->附加库目录中添加“D:\MySQL\mysql-8.0.37-winx64\lib”目录。
打开项目属性页面,在连接器>输入->附加依赖项添加“libmysql.lib”目录。
将libmysql.dll文件拷贝到项目的bin目录下。
2、接口介绍
2.1、MySql初始化及数据清理
2.1.1、mysql_library_init接口说明
mysql_library_init 用于初始化整个 MySQL 客户端库。这包括全局变量、内存分配器以及其他与库相关的初始化操作。这个函数通常在程序的开始调用一次,并且应该在任何 MySQL 客户端库函数(如 mysql_init)被调用之前调用。使用方式为mysql_library_init(0, 0, 0);
函数原型
int mysql_library_init(int argc, char **argv, char **groups);
参数说明
argc:命令行参数的数量。
argv:指向命令行参数的指针数组。
groups:一个指向以空字符分隔的组名列表的指针,这些组名指定了要读取的配置文件的部分。如果为 NULL,则读取默认组(通常是 client)。
返回值
如果初始化成功,返回 0。
如果初始化失败,返回非零值。
2.1.2、mysql_library_end接口说明
mysql_library_end和mysql_library_init配套使用,一般在程序退出时调用。
2.1.3、mysql_init接口说明
mysql_init 用于初始化一个 MYSQL 连接句柄。这个句柄将用于后续的数据库连接和查询操作。每次需要与数据库建立连接时,都需要调用这个函数来创建一个新的 MYSQL 连接句柄。
函数原型
MYSQL* mysql_init(MYSQL* mysql)
参数说明
mysql:这是一个指向 MYSQL 结构体的指针。如果传入的是 NULL 指针,则 mysql_init 会自动分配一个新的 MYSQL 结构体并返回其指针;如果传入的是一个已存在的 MYSQL 结构体指针,则该函数会初始化该结构体。
返回值
成功时,返回一个指向已初始化 MYSQL 结构体的指针。
失败时,返回 NULL。通常,当系统内存不足时,mysql_init 会返回 NULL。
2.1.4、mysql_close接口说明
mysql_close和mysql_init配套使用,用于关闭先前通过 mysql_init 初始化的 MYSQL 连接句柄,并释放与该连接相关的所有资源。这个函数在数据库操作完成后调用,以确保连接被正确关闭,并且不会留下任何悬挂的资源或连接。
使用实例
int main()
{mysql_library_init(0, 0, 0);MYSQL* mysql = mysql_init(0);mysql_close(mysql);mysql_library_end();
}
2.2、MySql数据库链接
2.2.1、mysql_real_connect接口说明
mysql_real_connect 是MySQL C API中用于连接到MySQL数据库服务器的一个函数。它提供了一个比 mysql_connect 更加灵活和详细的接口,允许你指定更多的连接参数。
函数原型
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag);
参数说明
MYSQL *mysql:这是一个已经初始化的MYSQL结构体指针,用于存储连接和查询结果。通常通过mysql_init()函数初始化。
const char *host:MySQL服务器的主机名或IP地址。如果为NULL或字符串"localhost",则连接被视为与本地主机的连接。
const char *user:连接MySQL服务器的用户名。如果为NULL或空字符串"",用户将被视为当前用户。在UNIX环境下,它是当前的登录名;在Windows ODBC下,必须明确指定当前用户名。
const char *passwd:连接MySQL服务器的密码。如果为NULL,仅会对该用户的(拥有1个空密码字段的)用户表中的条目进行匹配检查。密码加密将由客户端API自动处理。
const char *db:连接MySQL服务器后要使用的数据库名。如果为NULL,连接会将默认的数据库设为该值。
unsigned int port:MySQL服务器连接端口,默认为3306。如果指定了非0值,则使用该值作为TCP/IP连接的端口号。
const char *unix_socket:UNIX域套接字文件路径。如果不是NULL,该字符串描述了应使用的套接字或命名管道。
unsigned long client_flag:用于设置连接选项。通常设置为0,但也可以设置为特定标志的组合以允许特定功能。
返回值
如果连接成功,mysql_real_connect返回一个指向MYSQL结构体的指针,该指针代表与MySQL服务器的连接。
如果连接失败,返回NULL。
2.2.2、mysql_options接口说明
mysql_options是一个用于设置额外的连接选项并影响连接行为的函数,经常用于设置链接超时、自动重连。
函数原型
int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg);
参数说明
MYSQL *mysql:这是一个指向已经初始化的 MYSQL 结构体的指针。
enum mysql_option option:这是一个枚举类型,指定了要设置的选项。MySQL C API 定义了许多这样的选项,例如 MYSQL_OPT_CONNECT_TIMEOUT、MYSQL_OPT_READ_TIMEOUT、MYSQL_OPT_WRITE_TIMEOUT、MYSQL_OPT_COMPRESS、MYSQL_OPT_LOCAL_INFILE 等。
const char *arg(或对于 mysql_options4 的可变参数):这是与所选选项相关联的参数。它的类型和含义取决于 option 参数的值。例如,对于 MYSQL_OPT_CONNECT_TIMEOUT,参数应该是一个指向表示秒数的整数的指针(但通常通过类型转换传递为 const char *,因为实际实现可能接受 void * 并进行内部转换)。
返回值
如果成功,mysql_options 返回 0。
如果失败(例如,因为传递了无效的选项或参数),它返回非零值。
使用实例
mysql_library_init(0, 0, 0);MYSQL* mysql = mysql_init(0);const char* host = "127.0.0.1"; const char* user = "root";const char* pass = "luoboshou123";const char* db = "db_demo"; //数据库名称//设定超时3秒int to = 3;int re = mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &to);if (re != 0){cout << "mysql_options failed!" << mysql_error(mysql) << endl;}//自动重连int recon = 1;re = mysql_options(mysql, MYSQL_OPT_RECONNECT, &recon);if (re != 0){cout << "mysql_options failed!" << mysql_error(mysql) << endl;}if (!mysql_real_connect(mysql, host, user, pass, db, 3306, 0, 0)){cout << "mysql connect failed!" << mysql_error(mysql) << endl;}else{cout << "mysql connect success!" << endl;}for (int i = 0; i < 1000; i++){int re = mysql_ping(mysql);if (re == 0){cout << host << ":mysql ping success!" << endl;}else{cout << host << ":mysql ping failed! " << mysql_error(mysql) << endl;}this_thread::sleep_for(1s);}mysql_close(mysql);mysql_library_end();
2.3、数据库查询
2.3.1、mysql_real_query接口说明
mysql_real_query 是 MySQL C API 中的一个函数,用于向 MySQL 数据库服务器发送一个 SQL 查询。
函数原型
int mysql_real_query(MYSQL *mysql, const char *query, unsigned long length)
参数说明
mysql:这是一个指向已经通过 mysql_init 初始化并通过 mysql_real_connect 成功连接到数据库的 MYSQL 连接对象的指针。
query:这是一个指向包含要执行的 SQL 语句的字符串的指针。
length:这是 query 字符串的长度(以字节为单位)。如果你传递的是以空字符('\0')结尾的 C 字符串,你可以使用 strlen(query) 来获取这个长度。但是,如果你处理的是二进制数据或者不想依赖空字符来终止字符串,你应该明确指定长度。
返回值
如果查询成功执行,mysql_real_query 返回 0。
2.3.2、mysql_affected_rows接口说明
mysql_affected_rows 函数返回上一个执行成功的 INSERT、UPDATE 或 DELETE 语句所影响的行数。这对于需要统计或验证操作结果的场景非常有用
函数原型
my_ulonglong mysql_affected_rows(MYSQL *mysql)
参数说明
mysql:这是一个指向已经通过 mysql_init 初始化并通过 mysql_real_connect 成功连接到数据库的 MYSQL 连接对象的指针。
返回值
返回一个 my_ulonglong 类型的值,表示最近一次执行 INSERT、UPDATE 或 DELETE 语句所影响的行数。
2.3.3、mysql_error接口说明
mysql_error 是 MySQL C API 中的一个函数,用于获取最近一次 MySQL 函数调用产生的错误消息。当你调用 MySQL 的某个函数(如 mysql_query, mysql_store_result, mysql_real_query 等)并且该函数返回错误时,你可以使用 mysql_error 来获取关于该错误的详细信息。
函数原型
const char *mysql_error(MYSQL *mysql)
参数说明
mysql:这是一个指向已经通过 mysql_init 初始化并通过 mysql_real_connect(或 mysql_connect,尽管这是较旧的函数)成功连接到数据库的 MYSQL 连接对象的指针。
返回值
返回一个指向描述最近一次错误的字符串的指针。如果最近一次 MySQL 函数调用成功,没有产生错误,返回的字符串可能是一个空字符串("")或者表示没有错误的消息(这取决于 MySQL 的版本和配置)。
2.3.4、mysql_use_result接口说明
mysql_use_result 是 MySQL C API 中的一个函数,用于逐行获取查询结果集。这个函数与 mysql_store_result 相对应,但它们在处理大型结果集时的工作方式有所不同。
函数原型
MYSQL_RES *mysql_use_result(MYSQL *mysql)
参数说明
mysql:这是一个指向已经通过 mysql_init 初始化并通过 mysql_real_connect 成功连接到数据库的 MYSQL 连接对象的指针。
返回值
如果成功,返回一个指向 MYSQL_RES 结果集的指针,你可以使用这个结果集来逐行获取查询结果。
如果失败,返回 NULL。此时,你可以通过调用 mysql_error(mysql) 来获取错误消息。
2.3.5、mysql_store_result接口说明
mysql_store_result 是 MySQL C API 中的一个函数,用于从服务器检索查询的全部结果集并将其存储在客户端。
函数原型
MYSQL_RES *mysql_store_result(MYSQL *mysql)
参数说明
mysql:这是一个指向已经通过 mysql_init 初始化并通过 mysql_real_connect 成功连接到数据库的 MYSQL 连接对象的指针
返回值
如果成功,返回一个指向 MYSQL_RES 结构体的指针,该结构体包含了查询结果集的所有信息。你可以使用 mysql_fetch_row、mysql_num_rows、mysql_num_fields 等函数来访问和处理这个结果集。
如果失败(例如,由于内存不足或查询失败),返回 NULL。此时,你可以通过调用 mysql_error(mysql) 来获取错误消息。
2.3.6、mysql_fetch_field接口说明
mysql_fetch_field 是 MySQL C API 中的一个函数,用于从结果集中获取当前字段的信息。
函数原型
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)
参数说明
result:这是通过 mysql_store_result 或 mysql_use_result 函数执行查询后获得的结果集。
返回值
成功时,mysql_fetch_field 返回一个指向 MYSQL_FIELD 结构体的指针,该结构体包含了当前字段的信息。
如果所有字段信息都已被检索完毕,或者发生错误(例如,结果集为空),则返回 NULL。
MYSQL_FIELD 结构体
MYSQL_FIELD 结构体通常包含以下字段(具体字段可能因 MySQL 版本而异):
name:字段的名称。
org_name:字段的原始名称(如果适用)。
table:字段所属的表的名称(如果适用)。
org_table:字段所属的原始表的名称(如果适用)。
db:字段所属的数据库的名称(如果适用)。
catalog:字段所属的目录的名称(如果适用,通常为空)。
def:字段的默认值(如果适用)。
length:字段的长度。
max_length:字段的最大可能长度。
name_length:字段名称的长度。
org_name_length:字段原始名称的长度(如果适用)。
table_length:字段所属表的名称的长度(如果适用)。
org_table_length:字段所属原始表的名称的长度(如果适用)。
db_length:字段所属数据库的名称的长度(如果适用)。
catalog_length:字段所属目录的名称的长度(如果适用)。
def_length:字段默认值的长度(如果适用)。
flags:字段的标志,这些标志可以是多个值的组合,用于描述字段的特性(例如,是否允许 NULL 值,是否是主键等)。
type:字段的类型(例如,MYSQL_TYPE_INT、MYSQL_TYPE_VARCHAR 等)。
decimals:字段的小数位数(对于数值类型字段)。
2.3.7、mysql_num_fields接口说明
mysql_num_fields 是 MySQL C API 中的一个函数,用于获取查询结果集中的字段数量。
函数原型
unsigned int mysql_num_fields(MYSQL_RES *result)
参数说明
result:这是通过 mysql_store_result 或 mysql_use_result 函数执行查询后获得的结果集。
返回值
mysql_num_fields 返回一个无符号整数,表示结果集中字段的数量。如果结果集为空或发生错误,返回值可能是 0,但更常见的做法是通过检查 mysql_store_result 或 mysql_use_result 的返回值来确认查询是否成功执行。
2.3.8、mysql_fetch_row接口说明
mysql_fetch_row 是 MySQL C API 中的一个函数,用于从结果集中获取下一行的数据。
函数原型
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
参数说明
result:这是通过 mysql_store_result 或 mysql_use_result 函数执行查询后获得的结果集。
返回值
mysql_fetch_row 返回一个 MYSQL_ROW 类型的值,这是一个指向字符串数组的指针,数组中的每个字符串代表结果集中当前行的一个字段(列)的值。如果所有行都已检索完毕,或者发生错误(例如,结果集为空),则返回 NULL。
MYSQL_ROW 实际上是一个 char** 类型的别名,它指向一个以空指针结尾的字符串数组。因此,你可以像处理普通的 C 字符串数组一样处理 MYSQL_ROW。
2.3.9、mysql_fetch_lengths接口说明
mysql_fetch_lengths 是 MySQL C API 中的一个函数,用于获取当前行中各字段值的长度。
函数原型
unsigned long *mysql_fetch_lengths(MYSQL_RES *result)
参数说明
result:这是通过 mysql_store_result 或 mysql_use_result 函数执行查询后获得的结果集。
返回值
mysql_fetch_lengths 返回一个指向无符号长整数数组的指针,数组中的每个元素代表结果集中当前行对应字段的长度(不包括任何终结 NULL 字符)。如果发生错误,或者当前行已经超出了结果集的范围(比如在调用 mysql_fetch_row 之前或在检索了结果集中的所有行之后调用 mysql_fetch_lengths),则返回 NULL。
2.3.10、mysql_fetch_field_direct接口说明
mysql_fetch_field_direct 是 MySQL C API 中的一个函数,用于从结果集中获取指定列的字段信息。
函数原型
MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int fieldnr)
参数说明
result:这是一个指向 MYSQL_RES 结构体的指针,该结构体包含了查询结果集的信息。这个结构体通常是通过调用 mysql_store_result 或 mysql_use_result 函数获得的。
fieldnr:这是要获取的字段的索引(从 0 开始)。索引值应该小于结果集中字段的总数,该总数可以通过调用 mysql_num_fields 函数获得。
返回值
mysql_fetch_field_direct 返回一个指向 MYSQL_FIELD 结构体的指针,该结构体包含了指定索引位置的字段的元数据。如果指定的索引超出了结果集中字段的范围,或者发生了其他错误,函数将返回 NULL。
2.3.11、mysql_free_result接口说明
mysql_free_result 是 MySQL C API 中的一个函数,用于释放由 mysql_store_result 或 mysql_use_result 函数分配的内存,这些内存用于存储从数据库查询返回的结果集。当你不再需要访问查询结果时,应该调用 mysql_free_result 来释放这些资源,以避免内存泄漏。
函数原型
void mysql_free_result(MYSQL_RES *result)
参数说明
result:这是一个指向 MYSQL_RES 结构体的指针,该结构体包含了查询结果集的信息。这个结构体通常是通过调用 mysql_store_result 或 mysql_use_result 函数获得的。
返回值
mysql_free_result 函数没有返回值。它直接操作传入的 MYSQL_RES 结构体指针,释放与该结果集相关的所有资源。在调用此函数之后,传入的 result 指针将不再有效,你不应该再尝试使用它。
2.4、使用实例
#include <iostream>
#include "mysql.h"
#include <thread>
#include <string>
#include <sstream>using namespace std;std::string GBKToUTF8(const char *data)
{string re = "";
#ifdef _WIN32//gbk转为unicode win utf16//1 统计转换后字节数int len = MultiByteToWideChar(CP_ACP, //转换的格式0, //默认的转换方式data, //输入的字节-1, //输出的字符串大小 -1 找'\0'0, //输出0 //输出的空间大小);if (len <= 0) return re;wstring udata;udata.resize(len);MultiByteToWideChar(CP_ACP, 0, data, -1, (wchar_t*)udata.data(), len);// 2 unicode 转 utf-8len = WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)udata.data(), -1, 0, 0,0, //失败默认替代字符0 //是否使用默认替代);if (len <= 0) return re;re.resize(len);WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)udata.data(), -1, (char*)re.data(), len, 0, 0);
#elsere.resize(1024);int inlen = strlen(data);Convert((char*)"gbk", (char*)"utf-8", (char*)data, inlen, (char*)re.data(), re.size());int outlen = strlen(re.data());re.resize(outlen);
#endifreturn re;
}std::string UTF8ToGBK(char *data)
{string re = "";
#ifdef _WIN32//utf8转为unicode win utf16//1 统计转换后字节数int len = MultiByteToWideChar(CP_UTF8, //转换的格式0, //默认的转换方式data, //输入的字节-1, //输出的字符串大小 -1 找'\0'0, //输出0 //输出的空间大小);if (len <= 0) return re;wstring udata;udata.resize(len);MultiByteToWideChar(CP_UTF8, 0, data, -1, (wchar_t*)udata.data(), len);// 2 unicode 转 GBKlen = WideCharToMultiByte(CP_ACP, 0, (wchar_t*)udata.data(), -1, 0, 0,0, //失败默认替代字符0 //是否使用默认替代);if (len <= 0) return re;re.resize(len);WideCharToMultiByte(CP_ACP, 0, (wchar_t*)udata.data(), -1, (char*)re.data(), len, 0, 0);
#elsere.resize(1024);int inlen = strlen(data);Convert((char*)"utf-8", (char*)"gbk", (char*)data, inlen, (char*)re.data(), re.size());int outlen = strlen(re.data());re.resize(outlen);
#endifreturn re;
}int main()
{mysql_library_init(0, 0, 0);MYSQL* mysql = mysql_init(0);const char* host = "127.0.0.1"; const char* user = "root";const char* pass = "luoboshou123";const char* db = "db_demo"; //数据库名称if (!mysql_real_connect(mysql, host, user, pass, db, 3306, 0, 0)){cout << "mysql connect failed!" << mysql_error(mysql) << endl;}else{cout << "mysql connect success!" << endl;}string strSql = "";int res = 0;//创建表strSql = "DROP TABLE IF EXISTS `t_user`";strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res != 0){cout << "mysql_query failed!" << mysql_error(mysql) << endl;}strSql = "CREATE TABLE IF NOT EXISTS `t_user` (\`id` INT unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\`user_name` varchar(128) NOT NULL DEFAULT '' COMMENT '登录名',\`password` varchar(512) NOT NULL DEFAULT '' COMMENT '密码',\`nick_name` varchar(128) NOT NULL DEFAULT '' COMMENT '昵称',\`user_no` varchar(128) NOT NULL DEFAULT '' COMMENT '身份证号',\`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0(正常);1(禁用)',\`phone` char(11) NOT NULL DEFAULT '' COMMENT '手机号',\PRIMARY KEY(`id`),\UNIQUE KEY `user_name` (`user_name`),\UNIQUE KEY `phone` (`phone`)\) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; ";strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res != 0){cout << "mysql_query failed!" << mysql_error(mysql) << endl;}//插入表数据strSql = "insert into t_user (user_name,password,nick_name,user_no,status,phone) values('张三11','12345678','红太阳','131024685941523145',0,'13465231510')";strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res == 0){int count = mysql_affected_rows(mysql);cout << "insert mysql_affected_rows " << count << endl;}else{cout << "insert failed!" << mysql_error(mysql) << endl;}for (int i = 0; i < 5; i++) {stringstream ss;ss << "insert into t_user (user_name,password,nick_name,user_no,status,phone) values('张三11";ss << i;ss << "','12345678','红太阳','131024685941523145',0,'1346523151";ss << i + 2;ss << "')";strSql = ss.str();strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res == 0){int count = mysql_affected_rows(mysql);cout << "insert mysql_affected_rows " << count << endl;}else{cout << "insert failed!" << mysql_error(mysql) << endl;}}//修改表数据strSql = "update t_user set `nick_name`='红太阳2' where id=1";strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res == 0){int count = mysql_affected_rows(mysql);cout << "update mysql_affected_rows " << count << endl;}else{cout << "update failed!" << mysql_error(mysql) << endl;}//删除表数据strSql = "delete from t_user where id=1";strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res == 0){int count = mysql_affected_rows(mysql);cout << "delete mysql_affected_rows " << count << endl;}else{cout << "delete failed!" << mysql_error(mysql) << endl;}//查询数据strSql = "select * from t_user";strSql = GBKToUTF8(strSql.c_str());res = mysql_real_query(mysql, strSql.c_str(), strSql.size());if (res != 0) {cout << "mysql_real_query faied! " << strSql << " " << mysql_error(mysql) << endl;}else{cout << "mysql_real_query success! " << strSql << endl;}MYSQL_RES* result = mysql_use_result(mysql);if (!result){cout << "mysql_use_result faied! " << mysql_error(mysql) << endl;}MYSQL_ROW row;int num = mysql_num_fields(result);while (row = mysql_fetch_row(result)){unsigned long* lens = mysql_fetch_lengths(result);for (int i = 0; i < num; i++){cout << mysql_fetch_field_direct(result, i)->name << ":";if (row[i])cout << UTF8ToGBK(row[i]);elsecout << "NULL";cout << ",";}cout << endl;}mysql_free_result(result);mysql_close(mysql);mysql_library_end();system("pause");
}
3、全网最全辅助类实现
3.1、MySqlHelper.h
#ifndef MYSQLHELPER_H
#define MYSQLHELPER_H#include <mutex>
#include <vector>
#include <map>
#include <string>
#include <mysql.h>struct MYSQL;
struct MYSQL_RES;
namespace db {typedef struct {const char* host;const char* user;const char* pass;const char* db;unsigned short port;unsigned long flag;} MYSQLCCONNECT;typedef std::vector<std::map<std::string, std::string>> DataTable;class MySqlHelper {public:static const MYSQLCCONNECT conn;private://基础方法-------------------------------------//初始化Mysql APIbool Init();//清理占用的所有资源void Close();//数据库连接 flag设置支持多条语句bool Connect(MYSQLCCONNECT conn, std::string& errMsg, int connectTimeout = 5, unsigned long flag = 0);//执行sql语句 if sqllen = 0; strlen获取字符长度bool Query(std::string sql, std::string& errMsg);//Mysql参数的设定 Connect之前调用bool Options(mysql_option opt, std::string& errMsg, const void* arg);//连接超时时间设置bool SetConnectTimeout(int sec, std::string& errMsg);//释放结果集占用的空间void FreeResult();//基础方法-------------------------------------public://常用方法-------------------------------------//执行增删改动作int ExecuteNonSql(const std::string& sql, std::string& errMsg);//执行单一结果的查询bool ExecuteSingleResult(const std::string& sql, std::string& refResult, std::string& errMsg);//结果集查询bool ExecuteResult(const std::string& sql, DataTable& refTable, std::string& errMsg, bool is_use = true);//常用方法-------------------------------------//事务接口-------------------------------------bool StartTransaction(std::string& errMsg);bool Commit(std::string& errMsg);bool RollBack(std::string& errMsg);//基于事务执行增删改动作int ExecuteNonSqlTransaction(const std::string& sql, std::string& errMsg);//基于事务执行单一结果的查询bool ExecuteSingleResultTransaction(const std::string& sql, std::string& refResult, std::string& errMsg);//基于事务进行结果集查询bool ExecuteResultTransaction(const std::string& sql, DataTable& refTable, std::string& errMsg, bool is_use = true);//事务接口-------------------------------------//字符集转换-------------------------------------std::string UTF8ToGBK(std::string& data);std::string GBKToUTF8(std::string& data);//字符集转换-------------------------------------//数据库链接状态bool isConn();private:MYSQL* mysql = 0;MYSQL_RES* result = 0;};
}#endif
3.2、MySqlHelper.cpp
#include "MySqlHelper.h"
#include <iostream>using namespace std;namespace db {const MYSQLCCONNECT MySqlHelper::conn = { "127.0.0.1","root","luoboshou123","db_demo" };bool MySqlHelper::Init(){Close();this->mysql = mysql_init(0);if (!this->mysql) {return false;}return true;}void MySqlHelper::Close(){FreeResult();if (this->mysql) {mysql_close(this->mysql);this->mysql = NULL;}}bool MySqlHelper::Connect(MYSQLCCONNECT conn, std::string& errMsg, int connectTimeout, unsigned long flag){if (!this->mysql && !Init()) {errMsg = "Mysql connect failed! mysql is not init! ";return false;}if (!SetConnectTimeout(connectTimeout, errMsg)) {return false;}if (!mysql_real_connect(this->mysql, conn.host, conn.user, conn.pass, conn.db, conn.port, 0, flag)) {errMsg = "Mysql connect failed! : " + string(mysql_error(this->mysql));return false;}return true;}bool MySqlHelper::Query(std::string sql, std::string& errMsg){if (!this->mysql) {errMsg = "Query failed: mysql is NULL";return false;}if (sql.empty()) {errMsg = "sql is null";return false;}sql = GBKToUTF8(sql);int re = mysql_real_query(mysql, sql.c_str(), (unsigned long)sql.length());if (re != 0) {errMsg = "mysql_real_query failed! : " + string(mysql_error(this->mysql));return false;}return true;}bool MySqlHelper::Options(mysql_option opt, std::string& errMsg, const void* arg){if (!this->mysql) {errMsg = "Options failed: mysql is NULL";return false;}int re = mysql_options(this->mysql, (mysql_option)opt, arg);if (re != 0) {errMsg = "mysql_options failed!: " + string(mysql_error(this->mysql));return false;}return true;}bool MySqlHelper::SetConnectTimeout(int sec, std::string& errMsg){return Options(MYSQL_OPT_CONNECT_TIMEOUT, errMsg, &sec);}int MySqlHelper::ExecuteNonSql(const std::string& sql, std::string& errMsg){int res = -1;if (!Connect(conn, errMsg)){goto END;}if (sql.empty()){errMsg = "sql is empty";goto END;}if (!Query(sql, errMsg)){goto END;}res = mysql_affected_rows(mysql);END:Close();return res;}bool MySqlHelper::ExecuteSingleResult(const std::string& sql, std::string& refResult, std::string& errMsg){bool res = true;MYSQL_ROW row;int num;if (!Connect(conn, errMsg)){res = false;goto END;}if (sql.empty()){errMsg = "sql is empty";res = false;goto END;}if (!Query(sql, errMsg)){res = false;goto END;}this->result = mysql_store_result(this->mysql);if (!this->result) {errMsg = "mysql_store_result failed!:" + string(mysql_error(this->mysql));res = false;goto END;}row = mysql_fetch_row(this->result);if (!row) {errMsg = "mysql_fetch_row : No data found";res = false;goto END;}//列的数量num = mysql_num_fields(this->result);if (num != 1){errMsg = "mysql_num_fields : fields not 1";res = false;goto END;}refResult = row[0];END:Close();return res;}bool MySqlHelper::ExecuteResult(const std::string& sql, DataTable& refTable, std::string& errMsg, bool is_use){bool res = true;MYSQL_ROW row;int num;if (!Connect(conn, errMsg)){res = false;goto END;}if (sql.empty()){errMsg = "sql is empty";res = false;goto END;}if (!Query(sql, errMsg)){res = false;goto END;}FreeResult();if (is_use) {this->result = mysql_use_result(mysql);}else {this->result = mysql_store_result(mysql);}num = mysql_num_fields(result);while (row = mysql_fetch_row(this->result)){if (!row) {res = false;goto END;}map<string, string> rowData;for (int i = 0; i < num; i++){string key, value;key = mysql_fetch_field_direct(result, i)->name;if (row != NULL) {value = row[i];value = UTF8ToGBK(value);}else {value = "";}rowData[key] = value;}refTable.push_back(rowData);}END:Close();return res;}void MySqlHelper::FreeResult(){if (this->result) {mysql_free_result(this->result);this->result = NULL;}}bool MySqlHelper::StartTransaction(std::string& errMsg){if (!Connect(conn, errMsg)){return false;}if (!Query("START TRANSACTION", errMsg)){return false;}if (!Query("set autocommit=0", errMsg)){return false;}return true;}bool MySqlHelper::Commit(std::string& errMsg){if (!Query("commit", errMsg)){return false;}if (!Query("set autocommit=1", errMsg)){return false;}Close();return true;}bool MySqlHelper::RollBack(std::string& errMsg){if (!Query("rollback", errMsg)){return false;}if (!Query("set autocommit=1", errMsg)){return false;}Close();return true;}int MySqlHelper::ExecuteNonSqlTransaction(const std::string& sql, std::string& errMsg){int res = -1;if (sql.empty()){errMsg = "sql is empty";goto END;}if (!Query(sql, errMsg)){goto END;}res = mysql_affected_rows(mysql);END:return res;}bool MySqlHelper::ExecuteSingleResultTransaction(const std::string& sql, std::string& refResult, std::string& errMsg){bool res = true;MYSQL_ROW row;int num;if (sql.empty()){errMsg = "sql is empty";res = false;goto END;}if (!Query(sql, errMsg)){res = false;goto END;}this->result = mysql_store_result(this->mysql);if (!this->result){errMsg = "mysql_store_result failed!:" + string(mysql_error(this->mysql));res = false;goto END;}row = mysql_fetch_row(this->result);if (!row) {errMsg = "mysql_fetch_row : No data found";res = false;goto END;}num = mysql_num_fields(this->result);if (num != 1){errMsg = "mysql_num_fields : fields not 1";res = false;goto END;}refResult = row[0];END:return res;}bool MySqlHelper::ExecuteResultTransaction(const std::string& sql, DataTable& refTable, std::string& errMsg, bool is_use){bool res = true;MYSQL_ROW row;int num;if (sql.empty()){errMsg = "sql is empty";res = false;goto END;}if (!Query(sql, errMsg)){res = false;goto END;}FreeResult();if (is_use) {this->result = mysql_use_result(mysql);}else {this->result = mysql_store_result(mysql);}num = mysql_num_fields(result);refTable.clear();while (row = mysql_fetch_row(this->result)){if (!row) {res = false;goto END;}map<string, string> rowData;for (int i = 0; i < num; i++){string key, value;key = mysql_fetch_field_direct(result, i)->name;if (row != NULL) {value = row[i];value = UTF8ToGBK(value);}else {value = "";}rowData[key] = value;}refTable.push_back(rowData);}END:return res;}bool MySqlHelper::isConn(){return mysql->net.vio;}std::string MySqlHelper::GBKToUTF8(std::string& data){string re = "";
#ifdef _WIN32//gbk转为unicode win utf16//1 统计转换后字节数int len = MultiByteToWideChar(CP_ACP, //转换的格式0, //默认的转换方式data.c_str(), //输入的字节-1, //输出的字符串大小 -1 找'\0'0, //输出0 //输出的空间大小);if (len <= 0) return re;wstring udata;udata.resize(len);MultiByteToWideChar(CP_ACP, 0, data.c_str(), -1, (wchar_t*)udata.data(), len);// 2 unicode 转 utf-8len = WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)udata.data(), -1, 0, 0,0, //失败默认替代字符0 //是否使用默认替代);if (len <= 0) return re;re.resize(len);WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)udata.data(), -1, (char*)re.data(), len, 0, 0);
#elsere.resize(1024);int inlen = strlen(data);Convert((char*)"gbk", (char*)"utf-8", (char*)data, inlen, (char*)re.data(), re.size());int outlen = strlen(re.data());re.resize(outlen);
#endifreturn re;}std::string MySqlHelper::UTF8ToGBK(std::string& data){string re = "";
#ifdef _WIN32//utf8转为unicode win utf16//1 统计转换后字节数int len = MultiByteToWideChar(CP_UTF8, //转换的格式0, //默认的转换方式data.c_str(), //输入的字节-1, //输出的字符串大小 -1 找'\0'0, //输出0 //输出的空间大小);if (len <= 0) return re;wstring udata;udata.resize(len);MultiByteToWideChar(CP_UTF8, 0, data.c_str(), -1, (wchar_t*)udata.data(), len);// 2 unicode 转 GBKlen = WideCharToMultiByte(CP_ACP, 0, (wchar_t*)udata.data(), -1, 0, 0,0, //失败默认替代字符0 //是否使用默认替代);if (len <= 0) return re;re.resize(len);WideCharToMultiByte(CP_ACP, 0, (wchar_t*)udata.data(), -1, (char*)re.data(), len, 0, 0);
#elsere.resize(1024);int inlen = strlen(data);Convert((char*)"utf-8", (char*)"gbk", (char*)data, inlen, (char*)re.data(), re.size());int outlen = strlen(re.data());re.resize(outlen);
#endifreturn re;}
}
3.3、调用实例
#include <iostream>
#include "mysql.h"
#include <thread>
#include <string>
#include <sstream>
#include "MySqlHelper.h"using namespace std;
using namespace db;int main()
{MySqlHelper helper;string errMsg;bool flag = false;//增删改实例//string sql = "insert into t_user (user_name,password,nick_name,user_no,status,phone) values('张三11','12345678','红太阳','131024685941523145',0,'13465231510')";string sql = "update t_user set nick_name='小王1' where id = 24";//string sql = "delete from t_user where id = 24";int iRes = 0;iRes = helper.ExecuteNonSql(sql, errMsg);if (iRes == -1) {cout << errMsg << endl;}cout << iRes << endl;//单一结果查询实例sql = "select count(*) from t_user";string refResult;flag = helper.ExecuteSingleResult(sql, refResult, errMsg);if (!flag) {cout << errMsg << endl;}cout << refResult << endl;//结果集查询实例DataTable dt;sql = "select * from t_user";flag = helper.ExecuteResult(sql, dt, errMsg);if (!flag) {cout << errMsg << endl;}for (int i = 0; i < dt.size(); i++) {cout << dt[i]["id"] << " ";cout << dt[i]["user_name"] << " ";cout << dt[i]["password"] << " ";cout << dt[i]["nick_name"] << " ";cout << dt[i]["user_no"] << " ";cout << dt[i]["status"] << " ";cout << dt[i]["phone"] << endl;}//事务实例helper.StartTransaction(errMsg);sql = "update t_user set nick_name='小事7' where id=20";helper.ExecuteNonSqlTransaction(sql, errMsg);sql = "update t_user set nick_name='小事8' where id=22";helper.ExecuteNonSqlTransaction(sql, errMsg);sql = "select count(*) from t_user";helper.ExecuteSingleResultTransaction(sql, refResult, errMsg);cout << refResult << endl;//helper.Commit(errMsg);helper.RollBack(errMsg);system("pause");
}