mysql C++API介绍

1.mysql_insert_id和LAST_INSERT_ID二者作用一样,均是返回最后插入值的ID 值

  • 使用场景

①LAST_INSERT_ID()返回最后一个INSERT或UPDATE语句中AUTO_INCREMENT列的值,在linux环境下使用
②在C++环境中使用mysql_insert_id

uint32_t CDBConn::GetInsertId()
{
	return (uint32_t)mysql_insert_id(m_mysql);
}
[sql] 
mysql> insert into bankaccount(name,balance) values('123', 1000);  
Query OK, 1 row affected (0.06 sec)  
  
mysql> insert into bankstatement(action, txdate, amt, toaccno, fromaccno) values  
('122', curdate(), 1000, 1, 2);  
Query OK, 1 row affected (0.00 sec)  
www.2cto.com  
mysql> select last_insert_id();  
+------------------+  
| last_insert_id() |  
+------------------+  
|                7 |  
+------------------+  
1 row in set (0.00 sec)  
  
mysql> select * from bankaccount;  
+-------+------+---------+  
| accno | name | balance |  
+-------+------+---------+  
|     1 | 张三 |     200 |  
|     2 | 李四 |     900 |  
|     3 | 123  |    1000 |  
|     4 | 123  |    1000 |  
+-------+------+---------+  
4 rows in set (0.00 sec)  
 www.2cto.com  
mysql> select * from bankstatement;  
+----+--------------+------------+------+---------+-----------+  
| id | action       | txdate     | amt  | toaccno | fromaccno |  
+----+--------------+------------+------+---------+-----------+  
|  1 | 开户         | 2012-10-14 |  100 |    NULL |         1 |  
|  2 | 开户         | 2012-10-14 | 1000 |    NULL |         2 |  
|  3 | 查找账户信息 | 2012-10-14 |    0 |    NULL |         2 |  
|  4 | 查找账户信息 | 2012-10-14 |    0 |    NULL |         1 |  
|  5 | 转账         | 2012-10-14 |  100 |       1 |         2 |  
|  6 | 122          | 2012-10-14 | 1000 |       1 |         2 |  
|  7 | 122          | 2012-10-14 | 1000 |       1 |         2 |  
+----+--------------+------------+------+---------+-----------+  
7 rows in set (0.00 sec)  

2. MYSQL *mysql_init(MYSQL *mysql)

mysql: 有两种情况,一般都采用第⑴种方法.
⑴参数传 NULL 值。
这种情况很显然,是 mysql_init() 函数内部申请了一片内存,然后返回了首
地址。
MYSQL *ms_conn = mysql_init(NULL);
用完记得要释放
mysql_close(ms_conn), ms_conn = NULL;
⑵参数传对象地址。
这种情况就是使用栈内存,mysql_init() 函数显然不应该给分配堆内存。
MYSQL ms_eg;
MYSQL *ms_conn = mysql_init(&ms_eg);
用完记得要释放
mysql_close(ms_conn), ms_conn = NULL;

3. 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_real_connect()尝试与运行在主机上的 MySQL 数据库引擎建立连接。在你能够 执 行 需 要 有 效 MySQL 连 接 句 柄 结 构 的 任 何 其 他 API 函 数 之 前 ,mysql_real_connect()必须成功完成

参数:

a) mysql: MYSQL 结构的地址。调用 mysql_real_connect()之前,必须调用
mysql_init()来初始化 MYSQL 结构。
b) host: 必须是主机名或 IP 地址。如果“host”是 NULL 或字符串"localhost",连
接将被视为与本地主机的连接。
c) passwd: 用户的密码。如果“passwd”是 NULL,仅会对该用户的(拥有 1 个空密
码字段的)用户表中的条目进行匹配检查。这样,数据库管理员就能按特定的
方式设置 MySQL 权限系统,根据用户是否拥有指定的密码,用户将获得不同
的权限。
d) db: 数据库名称。如果 db 为 NULL,连接会将默认的数据库设为该值。
e) port: 如果“port”不是 0,其值将用作 TCP/IP 连接的端口号。注意,“host”
参数决定了连接的类型。
f) unix_socket: 如果 unix_socket 不是 NULL,该字符串描述了应使用的套接字或命
名管道。注意,“host”参数决定了连接的类型。
g) client_flag: 通常为 0,但是,也能将其设置为下述标志的组合,以允许特定功
能:

在这里插入图片描述
返回值
如果连接成功,返回 MYSQL*连接句柄。如果连接失败,返回 NULL。对于成功的连
接,返回值与第 1 个参数的值相同。
错误
CR_CONN_HOST_ERROR
无法连接到 MySQL 服务器。
CR_CONNECTION_ERROR
无法连接到本地 MySQL 服务器。
CR_IPSOCK_ERROR
无法创建 IP 套接字。
CR_OUT_OF_MEMORY
内存溢出。
CR_SOCKET_CREATE_ERROR
无法创建 Unix 套接字。
CR_UNKNOWN_HOST
无法找到主机名的 IP 地址。
CR_VERSION_ERROR
协议不匹配,起因于:试图连接到具有特定客户端库(该客户端库使用了不同
的协议版本)的服务器。如果使用很早的客户端库来建立与较新的服务器(未
使用“–old-protocol”选项开始的)的连接,就会出现该情况。
CR_NAMEDPIPEOPEN_ERROR
无法在 Windows 平台下创建命名管道。
CR_NAMEDPIPEWAIT_ERROR
在 Windows 平台下等待命名管道失败。
CR_NAMEDPIPESETSTATE_ERROR
在 Windows 平台下获取管道处理程序失败。
CR_SERVER_LOST
如果 connect_timeout> 0,而且在连接服务器时所用时间长于 connect_timeout
秒,或在执行 init-command 时服务器消失。

4. int mysql_query(MYSQL *mysql, const char *stmt_str)

作用
mysql_query() 向与指定的连接标识符关联的服务器中的当前活动数据库发送一条
查询,如果没有指定 link_identifier,则使用上一个打开的连接。如果没有打开的
连接,本函数会尝试无参数调用 mysql_connect() 函数来建立一个连接并使用之。
查询结果会被缓存。
参数
mysql: mysql_init 函数返回的指针。
stmt_str: 查询语句。
返回值
成功返回 0, 如果发生错误返回非 0.
错误
CR_COMMANDS_OUT_OF_SYNC
命令的执行顺序不正确。
CR_SERVER_GONE_ERROR
MySQL 服务器已经消失了。
CR_SERVER_LOST
查询期间与服务器的连接丢失。
CR_UNKNOWN_ERROR
发生未知错误。

5. MYSQL_RES *mysql_use_result(MYSQL *mysql)

作用
对于成功检索数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN),必须调用 mysql_store_result()或 mysql_use_result()。mysql_use_result()将初始化结果 集检索,但并不像 mysql_store_result()那样将结果集实际读取到客户端。它必须通过对 mysql_fetch_row()的调用,对每一行分别进行检索。这将直接从服务器读取结果,而不会将其保存在临时表或本地缓冲区内,与 mysql_store_result()相比,速度更快而且使用的内存也更少。客户端仅为当前行和通信缓冲区分配内存,分配的内存可增加到 max_allowed_packet 字节。
参数
mysql: mysql_init 函数返回的指针。
返回值
MYSQL_RES 结果结构。如果出现错误,返回 NULL。

6. MYSQL_RES *mysql_store_result(MYSQL *mysql)

作用
对于成功检索了数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE等),必须调用 mysql_store_result()或 mysql_use_result() 。对于其他查询,不需要调用 mysql_store_result()或 mysql_use_result(),但是如果在任何情况下均调用了mysql_store_result() , 它 也 不 会 导 致 任 何 伤 害 或 性 能 降 低 。 通 过 检 查mysql_store_result()是否返回 0,可检测查询是否没有结果集(以后会更多)。如果希望了解查询是否应返回结果集,可使用 mysql_field_count()进行检查“mysql_field_count()”。mysql_store_result()将查询的全部结果读取到客户端,分配 1 个 MYSQL_RES 结构,并将结果置于该结构中。如果查询未返回结果集,mysql_store_result()将返回 Null 指针(例如,如果查询是 INSERT 语句)。如果读取结果集失败,mysql_store_result()还会返回 Null 指针。通过检查 mysql_error()是否返回非空字符串,mysql_errno()是否返回非 0 值,或mysql_field_count()是否返回 0,可以检查是否出现了错误。如果未返回行,将返回
空的结果集。(空结果集设置不同于作为返回值的空指针)。一旦调用mysql_store_result()并获得了不是 Null 指针的结果,可调用 mysql_num_rows()来找出结果集中的行数。可以调用 mysql_fetch_row()来获取结果集中的行,或调用 mysql_row_seek()和mysql_row_tell()来获取或设置结果集中的当前行位置。一旦完成了对结果集的操作,必须调用 mysql_free_result()
参数
mysql: mysql_init 函数返回的指针。
返回值
具有多个结果的 MYSQL_RES 结果集合。如果出现错误,返回 NULL。通过检查 mysql_store_result() 是否返回 0(NULL) ,可检测查询是否没有结果集(以后会更多)。

  • 限制

注意缓存大小 MYSQL_OPT_MAX_ALLOWED_PACKET 默认 64

7. MYSQL_ROW mysql_fetch_row(MYSQL_RES*result)

作用
检索一个结果集合的下一行数据。当在 mysql_store_result()之后使用时,如果没有更多
的行可检索时,mysql_fetch_row()返回 NULL。当在 mysql_use_result()之后使用时,当没有更多的行可检索时或如果出现一个错误,mysql_fetch_row()返回 NULL。
在行中值的数量由 mysql_num_fields(result)给出。如果 row 保存了从一个对用
mysql_fetch_row() 调 用 返 回 的 值 , 指 向 该 值 的 指 针 作 为 row[0] 到
row[mysql_num_fields(result)-1]来存取。在行中的 NULL 值由 NULL 指针指出。
在行中字段值的长度可以通过调用 mysql_fetch_lengths()获得。空字段和包含 NULL
的字段长度都是 0;你可以通过检查该值的指针区分他们。如果指针是 NULL,字
段是 NULL;否则字段是空的。
参数
result: 返回一个结构为MYSQL_ROW的下一行结果, 如果没有要检索的行或发生错
误,则返回 NULL。
返回值
返回一个结构为 MYSQL_ROW 的下一行结果, 如果没有要检索的行或发生错
误,则返回 NULL。
错误
调用 mysql fetch_row()之间不会重置错误
CR_SERVER_LOST
查询期间与服务器的连接丢失。
CR_UNKNOWN_ERROR
发生未知错误。

  • 代码
bool CResultSet::Next()
{
	m_row = mysql_fetch_row(m_res);
	if (m_row)
	{
		return true;
	}
	else
	{
		return false;
	}
}

8. void mysql_free_result(MYSQL_RES *result)

作用
释放由 mysql_store_result(), mysql_use_result(), mysql_list_dbs()等为结果集分配的
内存。使用完结果集后,必须通过调用 mysql_free_result()释放它使用的内存。
释放结果集后不要尝试访问该结果集。
参数
result: 结果集
返回值

  • 代码
CResultSet::~CResultSet()
{
	if (m_res)
	{
		mysql_free_result(m_res);
		m_res = NULL;
	}
}

9. void mysql_close(MYSQL *mysql);

作用
关闭以前打开的连接。如果处理程序是由 mysql_init()或 mysql_connect()自动分配
的,mysql_close()还会释放 mysql 指向的连接处理程序。
参数
mysql: mysql_init 函数返回的指针。
返回值

10.int mysql_ping(MYSQL *mysql);

  • 描述:
    检查与服务端的连接是否正常。连接断开时,如果自动重新连接功能未被禁用,则尝试重新连接服务器。该函数可被客户端用来检测闲置许久以后,与服务端的连接是否关闭,如有需要,则重新连接。
  • 返回值:
    连接正常,返回0;如有错误发生,则返回非0值。返回非0值并不意味着服务器本身关闭掉,也有可能是网络原因导致网络不通。
  • 错误码:
    CR_COMMANDS_OUT_OF_SYNC 命令以不正确的顺序执行
    CR_SERVER_GONE_ERROR 服务器连接断开

11.int mysql_affected_rows(MYSQL* mysql)

  • 作用:

函数返回前一次 MySQL 操作所影响的记录行数。

  • 返回值

①DELETE语句执行成功,返回删除的行数,INSERT INTO TABLE VALUES 或者 INSERT INTO TABLES SET 都是返回插入成功的行数,这些是比较明确的。
②UPDATE语句执行成功时,则有可能也为0。如果要更新的值与原来的值相同,则affected_rows为0;否则,为更新的行数。
③INSERT INTO TABLE VALUES 或者 INSERT INTO TABLES SET 都是返回插入成功的行数,插入成功则返回1,否则返回0 。
④INSERT INTO TABLE VALUES … ON DUPLICATE KEY UPDATE … 语句执行成功后,则会有3种情况,当不存在唯一索引冲突时,执行INSERT操作,affected_rows结果为1;当存在主键冲突时,执行UPDATE操作,如果要更新的值与原来的相同,则affected_rows为0,否则为2。
⑤REPLACE INTO TABLE VALUES执行成功 ,如果没有存在唯一索引的冲突,则与INSERT操作没有什么区别affected_rows为1 ;如果存在主键冲突,则会DELETE再INSERT,所以affected_rows的值为2 。

  • 更加详细的返回值介绍

①For UPDATE statements, the affected-rows value by default is the number of rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to mysql_real_connect() when connecting to mysqld, the affected-rows value is the number of rows “found”; that is, matched by the WHERE clause.
②For REPLACE statements, the affected-rows value is 2 if the new row replaced an old row, because in this case, one row was inserted after the duplicate was deleted.
③For INSERT … ON DUPLICATE KEY UPDATE statements, the affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values. If you specify the CLIENT_FOUND_ROWS flag, the affected-rows value is 1 (not 0) if an existing row is set to its current values.
④Following a CALL statement for a stored procedure, mysql_affected_rows() returns the value that it would return for the last statement executed within the procedure, or 0 if that statement would return -1. Within the procedure, you can use ROW_COUNT() at the SQL level to obtain the affected-rows value for individual statements.
备注:mysql_affected_rows() returns a meaningful value for a wide range of statements. For details, see the description for ROW_COUNT() in Information Functions.

12.int mysql_real_query(MYSQL* mysql, const char* q , unsigned long length)

  • 与mysql_query的区别

①mysql_real_query可以包含二进制的数据,mysql_query不可以包含二进制数据(原因:(Binary data may contain the “\0” character, which mysql_query() interprets as the end of the statement string.)
②mysql_real_query比mysql_query更快,因为does not call strlen() on the statement string.

  • 返回值

0表示返回成功

13.int mysql_num_rows(MYSQL_RES* res)

  • 作用:

使用 mysql_num_rows 可以取得结果集中行的数目,返回结果集中有多少行数据。

  • 限制性

mysql_num_rows() 返回结果集中行的数目。此命令仅对 SELECT 语句有效。要取得被 INSERT,UPDATE 或者 DELETE 查询所影响到的行的数目,用 mysql_affected_rows()。

14.unsigned int mysql_num_fields(MYSQL_RES* result)

  • 作用:

返回结果集中字段的列数,也就是说每一行数据有多少列

15.MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES* res)

  • 作用:

返回采用MYSQL_FIELD结构的结果集的单个列数据。重复调用该函数,以检索关于结果集中所有列的信息。未剩余字段时,mysql_fetch_fields()返回NULL。

  • 代码示例
CResultSet::CResultSet(MYSQL_RES *res)
{
	m_res = res;

	// map table field key to index in the result array
	int num_fields = mysql_num_fields(m_res);
	MYSQL_FIELD *fields = mysql_fetch_fields(m_res);
	for (int i = 0; i < num_fields; i++)
	{
		// 多行
		m_key_map.insert(make_pair(fields[i].name, i));
	}
}
  • 与mysql_fetch_field(MYSQL_RES* res)的区别:

不带s的只返回单个数据,带s的返回的是一个数组

16. mysql_options(&mysql, MYSQL_OPT_RECONNECT, (char *)&value);

  • 作用

mysql_options是一个函数名,可用于设置额外的连接选项,并影响连接的行为。可多次调用该函数来设置数个选项。

  • 说明:
    在这里插入图片描述
    在这里插入图片描述
  • 代码
	//设定超时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);

	}
  • 返回值

返回0表示成功

17.unsigned long* mysql_fetch_lengths(MYSQL_RES* result)

  • 作用:

返回结果集当前行的所有列的数据长度

  • 代码
MYSQL_ROW row;
unsigned long *lengths;
unsigned int num_fields;
unsigned int i;
 
row = mysql_fetch_row(result);
if (row)
{
    num_fields = mysql_num_fields(result);	//拿到结果集这一行有多少列
    lengths = mysql_fetch_lengths(result);	//得到每一列的数据,放到数组里面
    for(i = 0; i < num_fields; i++)
    {
         printf("Column %u is %lu bytes in length.\n", i, lengths[i]);//打印数组元素的信息,也就是每一列的长度,但是不包括空的信息
    }
}
  • 适用点

无符号长整数的数组表示各列的大小(不包括任何终结NULL字符)。如果出现错误,返回NULL

18.int mysql_next_result(MYSQL *mysql)

  • 效果:
    return multiple result set
  • 原理
    reads the next statement result and returns a status to indicate whether more results exist. If mysql_next_result() returns an error, there are no more results.
  • 注意:

每次调用mysql_next_result之前调用一下mysql_free_result

数据结构原型

MYSQL : mysql 数据库连接句柄。在执行任何数据库操作之前首先就需要创建一个
MYSQL 结构。
MYSQL_RES : 执行查询语句(SELECT, SHOW, DESCRIBE, EXPLAIN)返回的结果。
MYSQL_ROW : 用来表示返回结果中的一行数据。由于每行数据格式不一致,因此使用此
结构来统一表示。调用 mysql_fetch_row()可从 MYSQL_RES 中返回一个
MYSQL_ROW 结构。
MYSQL_FIELD: 用来表示一个 field 信息的元数据(元数据,即描述数据的数据),包括
field name,field type 以及 field size 等。MYSQL_FIELD 不包含 field 的值
(MYSQL_ROW 真正保存各 field 的值)。
MYSQL_FIELD_OFFSET: field 在 row 中的索引值,从 0 开始。

typedef struct st_mysql {
	NET net; //通讯参数,网络相关
	gptr connector_fd; //加密套接字协议层
	//主机名, 数据库用户名,密码,Unix 套接字,版本,主机信息
	char *host,*user,*passwd,*unix_socket,*server_version,*host_info,*info,*db;
	unsigned int port,client_flag,server_capabilities;
	unsigned int protocol_version;
	unsigned int field_count; //字段个数
	unsigned int server_status; //数据库状态
	unsigned long thread_id; //数据库服务器中的连接 ID
	my_ulonglong affected_rows;
	my_ulonglong insert_id; //下一条记录的 ID
	my_ulonglong extra_info;
	unsigned long packet_length;
	enum mysql_status status;
	MYSQL_FIELD *fields; //字段列表
	MEM_ROOT field_alloc;
	my_bool free_me; //是否关闭
	my_bool reconnect; //是否自动连接
	struct st_mysql_options options;
	char scramble_buff[9];
	struct charset_info_st *charset;
	unsigned int server_language; //数据库语言
} MYSQL; //MYSQL 句柄

typedef struct st_mysql_res
{
	my_ulonglong row_count; // 结果集的行数
	unsigned int field_count, current_field;// 结果集的列数,当前列
	MYSQL_FIELD *fields; // 结果集的列信息
	MYSQL_DATA *data; // 结果集的数据
	MYSQL_ROWS *data_cursor; // 结果集的光标
	MEM_ROOT field_alloc; // 内存结构
	MYSQL_ROW row; // 非缓冲的时候用到
	MYSQL_ROW current_row; // mysql_store_result 时会用到,当前行
	unsigned long *lengths; // 每列的长度
	MYSQL *handle; // mysql_use_result 会用。
	my_bool eof; // 是否为行尾
} MYSQL_RES; //查询结果集

typedef char **MYSQL_ROW; // 以字符串数组的形式返回数据
typedef unsigned int MYSQL_FIELD_OFFSET; // 当前字段的偏移量量
typedef struct st_mysql_rows
{
	struct st_mysql_rows *next; // 下一条记录
	MYSQL_ROW data; // 当前行的数据
	unsigned long length; // 数据的长度
} MYSQL_ROWS; //mysql 的数据的链表节点。可见 mysql 的结果集是链表结构

typedef struct st_mysql_data
{
	my_ulonglong rows;
	unsigned int fields;
	MYSQL_ROWS *data;
	MEM_ROOT alloc;
} MYSQL_DATA; // 数据集的结构

typedef struct st_mysql_field
{
	char *name; //列名称
	char *table; //如果列是字段,列表
	char *def; //默认值(由 mysql_list_fields 设置)
	enum enum_field_types type; //类型的字段。Se mysql_com。h 的类型
	unsigned int length; //列的宽度
	unsigned int max_length; //选择集的最大宽度
	unsigned int flags; //div 标记集
	unsigned int decimals; //字段中的小数位数
} MYSQL_FIELD; //列信息的结构

typedef struct st_used_mem //结构为 once_alloc
{
	struct st_used_mem *next; //下一个块使用
	unsigned int left; //记忆留在块
	unsigned int size; //块的大小
} USED_MEM; //内存结构

typedef struct st_mem_root
{
	USED_MEM *free;
	USED_MEM *used;
	USED_MEM *pre_alloc;
	unsigned int min_malloc;
	unsigned int block_size;
	void (*error_handler)(void);
} MEM_ROOT; //内存结构

流程

  • DBcache
    ①初始化连接池的连接,设置多久ping一次和设置重连的设置
    ②初始化连接
    ③主循环无限mysql_ping

  • 其他服务器
    ①对mysql发送增删改查请求流程:

1)开启事务
2)set autocommit = 0;
----------------插入数据
3)回滚rollback
4)commit 提交
5)set autocommit = 1;

②接受发送请求回来的结果集流程,总数据存在MYSQL_RES

可以一次性发送多个请求,然后用do-while循环接受数据集,下面是怎么接受每个数据集:
①先获取结果集:MYSQL_RES* res = mysql_store_result(%mysql);
②mysql_num_field获取结果集的总行数
③用mysql_fetch_row遍历每一行的数据,每一行的数据信息存在MYSQL_ROW
④每次获取结果可以计时

以下为具体的使用案例代码

调用存储过程
	//1 创建存储过程
	sql = "CREATE PROCEDURE `p_test` (IN p_in INT,OUT p_out INT,INOUT  p_inout INT)\
	BEGIN\
	SELECT p_in,p_out,p_inout;\
	SET p_in = 100, p_out = 200,p_inout=300; \
	SELECT p_in,p_out,p_inout;\
	END";
	int re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << mysql_error(&mysql) << endl;
	}
	//2 定义变量并复制
	cout << "IN in=1 out=2 inout=3" << endl;
	sql = "SET @A=1;SET @B=2;SET @C=3;";
	re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << mysql_error(&mysql) << endl;
	}
	do
	{
		cout << "SET affect " << mysql_affected_rows(&mysql) << endl;
	}
	//0 还有结果, -1 没有结果 >1错误
	while (mysql_next_result(&mysql) == 0);

	//3 调用存储过程 call 
	sql = "call p_test(@A,@B,@C)";
	re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << mysql_error(&mysql) << endl;
	}
	cout << "In Proc:";
	do
	{
		MYSQL_RES *res = mysql_store_result(&mysql);
		if (!res)
			continue;

		//字段数量
		int fcount = mysql_num_fields(res);

		//打印结果集
		for (;;)
		{
			//提取一行记录
			MYSQL_ROW row = mysql_fetch_row(res);
			if (!row) break;
			for (int i = 0; i < fcount; i++)
			{
			
				if (row[i])
				{
					cout << row[i] << " ";
				}
				else
					cout << "NULL"<< " ";
			}
			cout << endl;

		}
		mysql_free_result(res);
	}
	//0 还有结果, -1 没有结果 >1错误
	while (mysql_next_result(&mysql) == 0);


	//4 获取存储过程的结果
	sql = "select @A,@B,@C";
	re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << mysql_error(&mysql) << endl;
	}
	MYSQL_RES *res = mysql_store_result(&mysql);
	cout << "out: ";
	MYSQL_ROW row = mysql_fetch_row(res);
	cout << " in=" << row[0];
	cout << " out=" << row[1];
	cout << " inout=" << row[2];
	mysql_free_result(res);
	cout << endl;

请求多个结果示例:
	//有多个返回结果
	do
	{
		cout << "[result]";
		MYSQL_RES * result = mysql_store_result(&mysql);
		if (result) //SELECT
		{
			cout << "SELECT mysql_num_rows = " << mysql_num_rows(result) << endl;
			mysql_free_result(result);
		}
		else  // INSERT UPDATE DELETE CREATE DROP truncate
		{
			// SELECT 出错 有字段无结果
			if (mysql_field_count(&mysql) > 0)
			{
				cout << "Not retrieve result! " <<mysql_error(&mysql)<< endl;
			}
			else //INSERT UPDATE DELETE CREATE DROP truncate
			{
				//等待服务器的处理结果
				cout << mysql_affected_rows(&mysql) << " rows affected!" << endl;
			}
		}
	}
	//取下一条结果 0表示有结果,-1表示没有结果,>1表示错误
	while (mysql_next_result(&mysql) == 0);
获取结果的计时
auto start = system_clock::now()
//balabal操作计时
auto end = system_clock::now();
auto dur = duration_cast<milliseconds>(end-start);
std::cout<<"插入或删除、查询数据所需时间:"<<dur.count()/1000<<"秒"<<std::endl;


//跨平台版本
uint64_t get_tick_count()
{
#if defined(WIN32)
	//没有GetTickCount()在49天溢出归零的问题,返回当前时间
	return GetTickCount64();
#else
	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC,&ts);
	return ts.tv_nsec/1000000 + ts.tv_sec*1000;
}
二进制文件的插入
	//1 初始化stmt mysql_stmt_init
	MYSQL_STMT *stmt = mysql_stmt_init(&mysql);
	if (!stmt)
	{
		cerr << "mysql_stmt_init failed!" << mysql_error(&mysql) << endl;
	}

	//2 预处理sql语句
	sql = "INSERT INTO `t_data` (name,data,size) VALUES(?,?,?)";
	if (mysql_stmt_prepare(stmt, sql.c_str(), sql.size()))
	{
		cerr << "mysql_stmt_prepare failed!" << mysql_stmt_error(stmt) << endl;
	}

	//3 打开并读取文件
	string filename = "mysql.jpg";
	
	//4 读取二进制
	fstream in(filename, ios::in | ios::binary);
	if (!in.is_open())
	{
		cerr << "file " << filename << " open failed!" << endl;
	}
	//5 文件指针移动到结尾处
	in.seekg(0, ios::end);
	//文件大小和文件二进制地址
	int filesize = in.tellg();
	//回到开头
	in.seekg(0, ios::beg);

	char *data = new char[filesize];
	int readed = 0; //已经读了多少
	while (!in.eof())
	{
		in.read(data+ readed, filesize- readed);
		//读取了多少字节
		if (in.gcount() <= 0)
			break;
		readed += in.gcount();
	}

	in.close();

	//6 绑定字段
	MYSQL_BIND bind[3] = { 0 };
	bind[0].buffer_type = MYSQL_TYPE_STRING;  //name 文件名
	bind[0].buffer = (char*)filename.c_str(); 
	bind[0].buffer_length = filename.size();

	bind[1].buffer_type = MYSQL_TYPE_BLOB;   //data 文件二进制内容
	bind[1].buffer = data; //二进制文件
	bind[1].buffer_length = filesize;

	//文件大小
	bind[2].buffer_type = MYSQL_TYPE_LONG;
	bind[2].buffer = &filesize;

	if (mysql_stmt_bind_param(stmt, bind) != 0)
	{
		cerr << "mysql_stmt_bind_param failed! " << mysql_stmt_error(stmt) << endl;
	}

	//7 执行stmt sql
	if (mysql_stmt_execute(stmt) != 0)
	{
		cerr << "mysql_stmt_execute failed! " << mysql_stmt_error(stmt) << endl;
	}
	
	//7.回收资源
	delete data;
	mysql_stmt_close(stmt);

完成对数据库中二进制图片的读取并存储为文件MYSQL_TYPE_BLOB的形式
	//1 创建好存放二进制数据的表 t_data
	sql = "CREATE TABLE IF NOT EXISTS `t_data` (\
		`id` int AUTO_INCREMENT,\
		`name` varchar(1024),\
		`data` blob,\
		`size` int,\
		PRIMARY KEY(`id`))";

	int re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << mysql_error(&mysql) << endl;
	}

	//2 清空表 truncate t_data
	sql = "truncate t_data";
	re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cerr << mysql_error(&mysql) << endl;
	}

	//3 初始化stmt mysql_stmt_init
	MYSQL_STMT *stmt = mysql_stmt_init(&mysql);
	if (!stmt)
	{
		cerr << "mysql_stmt_init failed!" << mysql_error(&mysql) << endl;
	}

	//4 预处理sql语句
	sql = "INSERT INTO `t_data` (name,data,size) VALUES(?,?,?)";
	if (mysql_stmt_prepare(stmt, sql.c_str(), sql.size()))
	{
		cerr << "mysql_stmt_prepare failed!" << mysql_stmt_error(stmt) << endl;
	}

	//5 打开并读取文件
	string filename = "mysql.jpg";


	
	//读取二进制
	fstream in(filename, ios::in | ios::binary);
	if (!in.is_open())
	{
		cerr << "file " << filename << " open failed!" << endl;
	}
	//文件指针移动到结尾处
	in.seekg(0, ios::end);
	//文件大小和文件二进制地址
	int filesize = in.tellg();
	//回到开头
	in.seekg(0, ios::beg);

	char *data = new char[filesize];
	int readed = 0; //已经读了多少
	while (!in.eof())
	{
		in.read(data+ readed, filesize- readed);
		//读取了多少字节
		if (in.gcount() <= 0)
			break;
		readed += in.gcount();
	}

	in.close();

	//6 绑定字段
	MYSQL_BIND bind[3] = { 0 };
	bind[0].buffer_type = MYSQL_TYPE_STRING;  //绑定name 文件名
	bind[0].buffer = (char*)filename.c_str(); 
	bind[0].buffer_length = filename.size();

	bind[1].buffer_type = MYSQL_TYPE_BLOB;   //绑定data 文件二进制内容
	bind[1].buffer = data; //二进制文件
	bind[1].buffer_length = filesize;

	//文件大小
	bind[2].buffer_type = MYSQL_TYPE_LONG;	//绑定文件大小
	bind[2].buffer = &filesize;

	if (mysql_stmt_bind_param(stmt, bind) != 0)
	{
		cerr << "mysql_stmt_bind_param failed! " << mysql_stmt_error(stmt) << endl;
	}

	//7 执行stmt sql
	if (mysql_stmt_execute(stmt) != 0)
	{
		cerr << "mysql_stmt_execute failed! " << mysql_stmt_error(stmt) << endl;
	}
	delete data;
	mysql_stmt_close(stmt);


	//8 查询二进制数据,并保存问文件
	sql = "select * from t_data";
	re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cerr << "mysql query failed!" << mysql_error(&mysql) << endl;
	}
	//获取结果集
	MYSQL_RES  *res = mysql_store_result(&mysql);
	if (!res)
	{
		cerr << "mysql_store_result failed!" << mysql_error(&mysql) << endl;
	}
	//取一行数据
	MYSQL_ROW row = mysql_fetch_row(res);
	if (!row)
	{
		cerr << "mysql_fetch_row failed!" << mysql_error(&mysql) << endl;
	}
	cout << row[0] << " " << row[1]<<" " << row[3] << endl;

	//获取每列数据的大小
	unsigned long *lens = mysql_fetch_lengths(res);
	int fnum = mysql_num_fields(res);
	for (int i = 0; i < fnum; i++)
	{
		cout << "["<<lens[i] << "]";
	}
	filename = "out_";
	filename += row[1];
	fstream out(filename, ios::out|ios::binary);
	if (!out.is_open())
	{
		cerr << "open file  " << filename << " failed!" << endl;
	}
	out.write(row[2], lens[2]);
	out.close();

获取一行的数据,将这一行的每列数据放到容器里面
	//获取一行数据
	std::vector<LXData> LXMysql::FetchRow()
	{
		std::vector<LXData> re;
		if (!result)
		{
			return re;
		}
		MYSQL_ROW row = mysql_fetch_row(result);//row为一行的数据
		if (!row)
		{
			return re;
		}

		//列数
		int num = mysql_num_fields(result);//为列数
		unsigned long* lengths;
		lengths	= mysql_fetch_lengths(result);
		for (int i = 0; i < num; i++)
		{
			LXData data;			//每一个data都是列的数据
			data.data = row[i];		//data是个字符串
			data.size = lengths[i];	//size是字符串数据的长度,不包括空的信息
			re.push_back(data);
		}
		return re;
	}


#pragma once
namespace LX 
{
	struct LXData
	{
		const char * data = 0;
		int size = 0;
	};
}


//------------------------------
//main函数
int main()
{
	LXMysql my;
	//1 mysql 初始化
	cout << "my.Init() = "<<my.Init() << endl;
	my.SetConnectTimeout(3);	//连接超时秒
	my.SetReconnect(true);		//自动重连

	//2 连接mysql 如果没有调用Init 内部会自动调用
	if (my.Connect("127.0.0.1", "root", "123456", "laoxiaketang"))
	{
		cout << "my.Connect success!" << endl;
	}

	//3 执行sql语句创建表
	string sql = "";

	sql = "CREATE TABLE IF NOT EXISTS `t_video` \
			(`id` INT AUTO_INCREMENT, \
			`name` VARCHAR(1024) , \
			`data` BLOB,\
			`size` INT,PRIMARY KEY(`id`))";
	
	cout<<my.Query(sql.c_str())<<endl;


	//测试自动重连
	//sql = "set @TEST=1";
	//for (;;)
	//{
	//	cout << my.Query(sql.c_str())<<flush;
	//}


	//插入一条记录
	sql = "insert into t_video(name) values('test001')";
	cout << my.Query(sql.c_str()) << endl;
	cout << my.Query(sql.c_str()) << endl;
	cout << my.Query(sql.c_str()) << endl;
	cout << my.Query(sql.c_str()) << endl;
	cout << my.Query(sql.c_str()) << endl;
	cout << my.Query(sql.c_str()) << endl;

	//获取结果集
	sql = "select * from t_video";
	cout << my.Query(sql.c_str()) << endl;
	my.StoreResult();	//结果集本地全部存储
	
	for (;;)
	{
		//获取一行数据
		auto row = my.FetchRow();
		if (row.size() == 0)break;
		for (int i = 0; i < row.size(); i++)
		{
			if(row[i].data)
				cout << row[i].data<<" ";
		}
		cout << endl;
	}
	
	
	my.FreeResult();

	cout << my.Query(sql.c_str()) << endl;
	my.UseResult();		//开始接收结果集
	my.FreeResult();




	//清理资源
	my.Close();
    std::cout << "test_LXMysql!\n"; 
}
mysql的跨平台编码设置:utf-8和GBK

1)原生字符集:
https://blog.csdn.net/weixin_43679037/article/details/117447866
2)C++编码相关知识和API接口:
https://blog.csdn.net/weixin_43679037/article/details/120497491

示例代码(一小部分)

#include <iostream>
#include <mysql.h>
#include <thread>
using namespace std;
int main()
{
	//初始化mysql上下文
	MYSQL mysql;
	//单线程模式 mysql_init自动调用 mysql_library_init 线程不安全
	mysql_init(&mysql);
	const char *host = "127.0.0.1";
	//const char *host = "192.168.0.203";
	const char *user = "root";
	const char *pass = "123456";
	const char *db = "mysql";		//数据库名称
	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;
	}

	//user select * from user
	// 1 执行SQL语句
	const char *sql = "select * from user";
	// mysql_real_query  sql语句中可以包含二进制数据
	// mysql_query sql语句中只能是字符串
	// 0返回表示成功 
	int re = mysql_real_query(&mysql, sql, strlen(sql));

	// Commands out of sync; you can't run this command now 
	// 执行sql语句后,必须获取结果集并且清理
	// re = mysql_query(&mysql, sql);
	if (re != 0)
	{
		cout << "mysql_real_query faied! "<< sql<<" " << mysql_error(&mysql) << endl;
	}
	else
	{
		cout << "mysql_real_query success! " << sql << endl;
	}


	//2 获取结果集

	// mysql_use_result 不实际读取数据
	//MYSQL_RES* result = mysql_use_result(&mysql);
	//mysql_store_result 读取所有数据,注意缓存大小 MYSQL_OPT_MAX_ALLOWED_PACKET 默认 64M
	MYSQL_RES* result = mysql_store_result(&mysql);
	if (!result)
	{
		cout << "mysql_use_result faied! "  << mysql_error(&mysql) << endl;
	}

	//获取表字段
	MYSQL_FIELD *field = 0;
	while (field = mysql_fetch_field(result))
	{
		cout << "key:" << field->name << endl;
	}

	//获取表字段数量
	int fnum = mysql_num_fields(result);




	//3 遍历结果集
	MYSQL_ROW row;
	while (row = mysql_fetch_row(result))
	{
		unsigned long * lens = mysql_fetch_lengths(result);

		//cout<< lens[0] << "[" << row[0] << "," << row[1] << "]" << endl;
		for (int i = 0; i < fnum; i++)
		{
			cout << mysql_fetch_field_direct(result, i)->name << ":";
			if (row[i])
				cout << row[i];
			else
				cout << "NULL";
			cout<< ",";
		}
		cout <<"\n=========================================="<< endl;

	}

	//清理结果集
	mysql_free_result(result);



	mysql_close(&mysql);
	mysql_library_end();
	std::cout << "Hello World!\n";
	getchar();
}


  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值