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");
}