文章目录
- 1.mysql_insert_id和LAST_INSERT_ID二者作用一样,均是返回最后插入值的ID 值
- 2. MYSQL *mysql_init(MYSQL *mysql)
- 3. MYSQL *mysql_real_connect(MYSQL *mysql,
- 4. int mysql_query(MYSQL *mysql, const char *stmt_str)
- 5. MYSQL_RES *mysql_use_result(MYSQL *mysql)
- 6. MYSQL_RES *mysql_store_result(MYSQL *mysql)
- 7. MYSQL_ROW mysql_fetch_row(MYSQL_RES*result)
- 8. void mysql_free_result(MYSQL_RES *result)
- 9. void mysql_close(MYSQL *mysql);
- 10.int mysql_ping(MYSQL *mysql);
- 11.int mysql_affected_rows(MYSQL* mysql)
- 12.int mysql_real_query(MYSQL* mysql, const char* q , unsigned long length)
- 13.int mysql_num_rows(MYSQL_RES* res)
- 14.unsigned int mysql_num_fields(MYSQL_RES* result)
- 15.MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES* res)
- 16. mysql_options(&mysql, MYSQL_OPT_RECONNECT, (char *)&value);
- 17.unsigned long* mysql_fetch_lengths(MYSQL_RES* result)
- 18.int mysql_next_result(MYSQL *mysql)
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();
}