MySQL C API的使用
介绍及使用
MySQL C API(也称为 MySQL Connector/C)是用于与 MySQL 数据库交互的 C 语言 API。它提供了一组函数和结构体,允许你在 C 程序中连接到 MySQL 数据库服务器,并执行查询、插入、更新等数据库操作。
以下是 MySQL C API 的基本使用步骤:
1. 包含头文件:
在你的 C 代码中包含 MySQL C API 的头文件:
#include <mysql/mysql.h>
2. 初始化和连接:
在程序开始时,需要初始化 MySQL C API 并建立与数据库服务器的连接。以下是一个简单的例子:
c
// 这个函数初始化MySQL,并返回一个MYSQL指针。这个指针在后续的操作中都会使用到。
MYSQL *conn;
conn = mysql_init(NULL);
if (conn == NULL) {
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
//连接到数据库:mysql_real_connect()使用这个函数来连接到数据库。其中参数包括上一步得到的MYSQL指针,以及数据库的主机名、用户名、密码、数据库名等。
if (mysql_real_connect(conn, "localhost", "user", "password", "database", 0, NULL, 0) == NULL) {
fprintf(stderr, "mysql_real_connect() failed\n");
mysql_close(conn);
exit(1);
}
// 补充了解
// 最后三个参数大部分情况下为0,NULL,0即可,三个参数详细介绍如下
port:这是数据库服务端的端口号,默认是MySQL的默认端口3306。如果提供0,将使用默认端口;
unix_socket:这是Unix系统专用的,如果mysql服务器运行在本地,并使用了Unix socket,这个参数就指定了该socket的路径。对于运行在网络上的服务器,此参数通常为NULL;
client_flag:这是额外标志,通常为0。对于特殊情况,可以设置为一些特定的值,比如CLIENT_COMPRESS(在客户端和服务器间进行压缩),CLIENT_SSL(使用ssl连接),CLIENT_LOCAL_FILES(允许LOAD DATA LOCAL操作)等等。详情请查阅MySQL的官方文档。
为了兼容更多的使用场景,mysql_real_connect函数给出了很多参数,适合应对各种复杂的数据库连接情况。但是在实际使用中,大部分情况下,使用默认参数(port为0,unix_socket为NULL,client_flag为0)就足够了。
在这个例子中,使用 mysql_init
初始化 MySQL 对象,然后使用 mysql_real_connect
建立与 MySQL 服务器的连接。你需要提供主机名、用户名、密码和数据库名。
3. 执行查询:
一旦连接建立,你可以执行 SQL 查询。以下是一个简单的查询示例:
c
//mysql_query()使用这个函数来执行SQL查询。查询结果可以用后续的函数来获取。
if (mysql_query(conn, "SELECT * FROM your_table")) {
fprintf(stderr, "SELECT query failed: %s\n", mysql_error(conn));
mysql_close(conn);
exit(1);
}
//获取查询结果:mysql_store_result() 或 mysql_use_result()这两个函数可以获取查询结果。mysql_store_result()将所有的查询结果存储在客户端,mysql_use_result()则允许你一个接一个地获取结果行。
MYSQL_RES *result = mysql_store_result(conn); // 注意,返回值是指针
if (result == NULL) {
fprintf(stderr, "mysql_store_result() failed\n");
mysql_close(conn);
exit(1);
}
//遍历结果集:mysql_fetch_row()这个函数可以获取结果集中的一行。你可以在循环中使用它来遍历所有的结果行。
int num_fields = mysql_num_fields(result);
MYSQL_ROW row; //typedef char **MYSQL_ROW
while ((row = mysql_fetch_row(result))) {
for (int i = 0; i < num_fields; i++) {
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}
mysql_free_result(result);
// 补充了解
typedef struct MYSQL_RES {
uint64_t row_count;
MYSQL_FIELD *fields;
struct MYSQL_DATA *data;
MYSQL_ROWS *data_cursor;
unsigned long *lengths; /* column lengths of current row */
MYSQL *handle; /* for unbuffered reads */
const struct MYSQL_METHODS *methods;
MYSQL_ROW row; /* If unbuffered read */
MYSQL_ROW current_row; /* buffer to current row */
struct MEM_ROOT *field_alloc;
unsigned int field_count, current_field;
bool eof; /* Used by mysql_fetch_row */
/* mysql_stmt_close() had to cancel this result */
bool unbuffered_fetch_cancelled;
enum enum_resultset_metadata metadata;
void *extension;
} MYSQL_RES;
这个例子执行一个简单的 SELECT 查询,然后使用 mysql_store_result
获取查询结果,并使用 mysql_fetch_row
逐行读取结果集中的数据。
4. 插入、更新和删除:
你可以使用 mysql_query
函数执行插入、更新和删除等修改数据库的操作。以下是一个插入数据的示例:
c
if (mysql_query(conn, "INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2')")) {
fprintf(stderr, "INSERT query failed: %s\n", mysql_error(conn));
mysql_close(conn);
exit(1);
}
5. 清理结果集:
c
//清理结果集:mysql_free_result()当你处理完查询结果后,需要调用这个函数来清理结果集。
mysql_free_result(result);
mysql_close(conn);
6.关闭连接
在程序结束时,确保关闭与 MySQL 服务器的连接并释放资源:
c
mysql_close(conn);
这些是 MySQL C API 的基本用法示例。请注意,为了简洁起见,没有进行错误处理的详细检查。在实际应用中,应该更加详细地处理错误以确保程序的稳定性。
API封装
以下为个人在使用过程中,对API的进一步封装
cpp
class DataBase {
public:
~DataBase() {
Close(); // 析构函数自动关闭数据库
}
// 初始化,可以指定连接的 用户名,密码,数据存储库,host,port
void Init(string name, string pwd, string database, string host = "localhost", int port = 3306) {
mysql_init(&mysql_);
// 连接数据库
if (mysql_real_connect(&mysql_, host.c_str(), name.c_str(), pwd.c_str(), database.c_str(), port, NULL, 0) == NULL) {
cout << mysql_error(&mysql_) << endl;
cout << "connect error!" << endl;
exit(-1);
}
// 设置字符集编码,包含了character_set_connection为utf8mb4,因为库以及表采用的是utf8mb4字符集
if (!mysql_set_character_set(&mysql_, "utf8mb4"))
{
printf("New client character set: %s\n", mysql_character_set_name(&mysql_));
}
// 设置character_set_client 客户端字符集为GBK,因为命令行窗口是GBK编码,否则mysql 1366 error
// 设置character_set_results 查询结果集为GBK,因为命令行窗口是GBK编码,要对应起来,否乱码
if (!Query("set character_set_client = gbk") || !Query("set character_set_results = gbk")) {
cout << "set character_set_client or character_set_results gbk error:" << Error() << endl;
}
}
// 执行语句
bool Query(const string& query) {
// 成功0,失败非0
return !mysql_query(&mysql_, query.c_str());
}
// 释放结果集
void FreeResult() {
mysql_free_result(res_);
}
// 返回记录行数
int Rows() {
return mysql_num_rows(res_);
}
// 返回字段数量
int Cols() {
return mysql_num_fields(res_);
}
// 关闭数据库
void Close() {
mysql_close(&mysql_);
}
// 获取查询结果集
MYSQL_RES* GetResult() {
return res_ = mysql_store_result(&mysql_);
}
// 获取表字段
MYSQL_FIELD* GetFields() {
return mysql_fetch_fields(res_);
}
const char* Error() {
return mysql_error(&mysql_);
}
// 获取一行记录
MYSQL_ROW FetchRow() {
return row_ = mysql_fetch_row(res_);
}
// 不区分大小写进行比较字符串,主要用于字段名比较
bool InsensistiveStringCompare(const string& str1, const string& str2) {
string str1Cpy(str1);
string str2Cpy(str2);
transform(str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower);
transform(str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower);
return (str1Cpy == str2Cpy);
}
// 输出结果集,便于调试
void Show(const string& query) {
if (!Query(query)) {
cout << "show test error:" << Error() << endl;
exit(-1);
}
MYSQL_RES* res = GetResult();
if (!res) {
cout << "GetResult error:" << Error() << endl;
exit(-1);
}
int n = Rows(), m = Cols();
cout << "共" << n << "条记录," << m << "个字段" << endl;
MYSQL_ROW row;
string field;
vector<vector<string>> records(n + 1, vector<string>(m));
vector<int> max_len(m); // 记录每列数据的最大长度,便于格式化输出
int len = 0;
MYSQL_FIELD* fields = GetFields();
for (int i = 0; i < m; ++i) {
records[0][i] = fields[i].name; // 获取字段名
max_len[i] = (int)max(fields[i].name_length, fields[i].max_length); // 获取字段记录最大长度以及字段长度,记录最大值
}
for (int i = 1; i <= n; ++i) {
row = FetchRow();
for (int j = 0; j < m; ++j) {
if (row[j]) field = row[j];
else field = "NULL";
records[i][j] = field;
len = max(len, sizeof field);
}
}
for (int i = 0; i <= n; ++i) {
for (int j = 0; j < m; ++j) {
cout << setiosflags(ios::left) << setw(max_len[j] + 2) << records[i][j] << ' ';
}
cout << endl;
}
}
private:
MYSQL mysql_; // 数据库句柄
MYSQL_RES* res_; // 查询结果集合
MYSQL_ROW row_; // 记录结构体
};