MySQL数据库专栏(五)连接MySQL数据库C API篇

摘要


本篇文章主要介绍通过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-8
	len = 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);
#else
	re.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);
#endif
	return 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 转 GBK
	len = 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);
#else
	re.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);
#endif
	return 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]);
			else
				cout << "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 API
		bool 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-8
		len = 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);
#else
		re.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);
#endif
		return 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 转 GBK
		len = 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);
#else
		re.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);
#endif
		return 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");
}
相关推荐
黑色叉腰丶大魔王几秒前
《MySQL 数据库备份与恢复》
mysql
苏-言2 分钟前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
土豆湿3 分钟前
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
开发语言·javascript·css
Ljw...8 分钟前
索引(MySQL)
数据库·mysql·索引
界面开发小八哥10 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
菠萝咕噜肉i22 分钟前
超详细:Redis分布式锁
数据库·redis·分布式·缓存·分布式锁
长风清留扬24 分钟前
一篇文章了解何为 “大数据治理“ 理论与实践
大数据·数据库·面试·数据治理
OpsEye37 分钟前
MySQL 8.0.40版本自动升级异常的预警提示
数据库·mysql·数据库升级
Ljw...38 分钟前
表的增删改查(MySQL)
数据库·后端·mysql·表的增删查改
qystca38 分钟前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法