MYSQL 对 C/C++ 提供了 MYSQL 库用于操作数据库,Centos7 需要先行安装对应的文件:sudo yum install mysql-devel
。
使用 g++ 编译使用了该库的程序时需要加上 -L /usr/lib64/mysql -lmysqlclient
。
1. 建立 MYSQL 操作句柄
操作 MYSQL 需要使用库里提供的操作句柄,即一个 MYSQL
结构体。这个操作句柄几乎在所有接口函数中都要用到。
该句柄在使用前需要初始化,对应的接口函数为:
MYSQL* mysql_init(MYSQL* mysql)
如果参数 mysql
为空指针,则函数建立并初始化一个 MYSQL
变量,并返回其指针。如果参数为一个指向 MYSQL
结构体的指针,则函数对其进行初始化,并返回这个指针。
下面是使用示例:
MYSQL* connect_fd = mysql_init(nullptr);
2. 连接数据库
连接数据库的接口函数为:
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
为操作句柄,host
为数据库所在主机的 IP ,user
为连接的数据库用户,passwd
为这个用户的密码,db
是要连接的数据库名,port
为连接的主机的端口,unix_socket
通常为空指针,client_flag
定义了一些额外的选项,通常置 0 。最后两个参数的具体使用可以查看上面的文档链接。
调用成功返回操作句柄,即第一个参数,否则为空指针。
下面是使用示例:
mysql_real_connect(connect_fd, "localhost", "root", "", "db_name", 3306, nullptr, 0);
3. 设置当前连接使用的字符集
mysql 中字符集是个要注意的地方。MYSQL
库提供了设置当前连接使用的字符集的接口函数:
int mysql_set_character_set(MYSQL* mysql, const char* csname)
建议直接设成 utf-8
mysql_set_character_set(connect_fd, "utf8");
4. 执行 SQL 语句
执行 MYSQL 语句的接口函数如下:
int mysql_query(MYSQL* mysql, const char* stmt_str)
其中 stmt_str
为要执行的 SQL 语句。注意这里的 SQL 语句的末尾不能有 ;
。
调用成功返回 0
,失败返回非零值。
示例如下:
char sql[2048] = { 0 };
sprintf(sql, "INSERT INTO tb_name values(%d, %d, %d)", 1, 2, 3);
if(mysql_query(connect_fd, sql)) {
cout << "Error: mysql_query() failed!" << endl;
}
5. 查询 SQL 结果
查询结果
假如你执行的 SQL 语句会返回结果,例如 SELECT
语句,那么可以用下面的接口函数来接受结果:
MYSQL_RES* mysql_store_result(MYSQL* mysql)
其中 MYSQL_RES
结构体用于存储 SQL 语句执行的结果,这个结果被称为结果集(result set)。
在执行了所有可能返回查询结果的 SQL 语句(SELECT
、SHOW
、DECRIBE
、EXPLAIN
、CHECK TABLE
)后,都必须执行 mysql_store_result()
或 mysql_use_result()
。在最后也必须调用下一节介绍的接口函数去释放结果集。
如果调用成功,函数返回指向结果集的指针,否则返回空指针。注意返回空指针可能是因为该 SQL 语句就不返回结果(例如 INSERT
),或者是函数内部出错。
如果 SQL 查询结果里没有一行数据(例如没有任何一条 SQL 数据匹配到你的查询条件),则返回的结果集为空结果集。注意空结果集和空指针是不一样的。
查看结果的行数和列数
假如函数返回了正确的结果集,你可以用下面两个接口函数来查看结果集中的行数和列数:
my_ulonglong mysql_num_rows(MYSQL_RES* result)
unsigned int mysql_num_fields(MYSQL_RES* result)
取出一行结果
下面的接口函数用于从结果集中取出一行结果:
MYSQL_ROW mysql_fetch_row(MYSQL_RES* result)
注意每调用一次这个函数,下次返回的结果就是下一行数据。如果所有行都取出后,再次调用该函数返回空指针。
MYSQL_ROW
结构用于表示一行结果,这个结构其实是一个字符串数组,例如我看源码里 MYSQL_ROW
其实就是 char **
typedef 来的。数组的长度就是查询结果的列数。
当前行中每一列的具体长度
而下面这个函数用于获取当前行中每一列的长度,即上一步返回的 MYSQL_ROW
数组中每个字符串的长度。
unsigned long* mysql_fetch_lengths(MYSQL_RES* result)
该函数的返回值也是一个数组,数组长度就是列的个数。
通过这一字段可以准确判断某个字段的长度,正常情况下 MYSQL_ROW
中每个字符串结尾都有 \0
,无需额外判断这个字符串的长度,但假如其中存储的是二进制数据(即\0
也可能是数据)就必须得通过这个函数判断字符串的真实长度,再进行后续操作。
假如数据库中某个字段的值为空,则 MYSQL_ROW
数组中对应的字符串为空字符串 ,且 mysql_fetch_lengths()
返回的数组中对应的长度为 0 。但假如数据库中某个字段的值为 NULL
,则 MYSQL_ROW
数组中对应的字符串为空指针,而长度同样为 0 。注意区分两者的区别。
下面的示例应用了这一节介绍的接口函数:
MYSQL_RES* my_res = mysql_store_result(connect_fd);
unsigned int rows = mysql_num_rows(my_res);
unsigned int cols = mysql_num_cols(my_res);
MYSQL_ROW my_row;
for(int i = 0; i < rows; i++) {
my_row = mysql_fetch_row(my_res);
for(int j = 0; j < cols; j++) {
cout << my_row[j] << endl;
}
}
6. 释放结果集
在使用完结果集后,必须调用下面的接口函数去释放结果集占用的内存,注意 MYSQL_RES
是一个黑盒结构,不能由用户自行释放。
void mysql_free_result(MYSQL_RES* result)
7. 关闭操作句柄
在使用完后需要调用下面的接口函数来关闭操作句柄:
void mysql_close(MYSQL* mysql)
如果操作句柄是由 mysql_init()
分配的空间,则同时空间也被释放。