MySQL常用API
MySQL常用API
在 C 语言中操作 MySQL 数据库依赖于 MySQL 官方提供的 C API(也称为 libmysqlclient
),这套 API 包含一系列函数,覆盖从 “初始化连接” 到 “释放资源” 的全流程。以下按操作顺序分类介绍核心函数,包括函数原型、参数、返回值及使用场景:
一、连接初始化与关闭
这类函数用于初始化 MySQL 连接句柄、建立连接及释放资源,是所有操作的基础。
1. mysql_init
- 原型:
MYSQL *mysql_init(MYSQL *mysql);
- 功能:初始化 MySQL 连接句柄(
MYSQL
结构体),分配内存并设置默认属性。 - 参数:
mysql
:若为NULL
,函数会自动分配新的MYSQL
结构体;若传入已存在的句柄,会重置该句柄(清空之前的连接信息)。
- 返回值:
- 成功:返回初始化后的
MYSQL*
句柄; - 失败:返回
NULL
(通常因内存不足)。
- 成功:返回初始化后的
- 示例:
MYSQL *conn = mysql_init(NULL); // 初始化新句柄 if (conn == NULL) {fprintf(stderr, "初始化失败:内存不足\n"); }
2. mysql_real_connect
- 原型:
MYSQL *mysql_real_connect(MYSQL *mysql, // 已初始化的句柄(mysql_init返回值)const char *host, // MySQL服务器地址(localhost/IP/域名)const char *user, // 登录用户名(如root)const char *passwd, // 登录密码const char *db, // 要连接的数据库名(NULL表示不指定)unsigned int port, // 端口号(默认3306,传0使用默认)const char *unix_socket, // Unix套接字(仅Linux/macOS,NULL表示不使用)unsigned long client_flag // 客户端标志(0表示默认,特殊需求如CLIENT_SSL) );
- 功能:与 MySQL 服务器建立实际连接,验证身份并选择数据库。
- 返回值:
- 成功:返回与参数
mysql
相同的句柄; - 失败:返回
NULL
(错误信息通过mysql_error
获取)。
- 成功:返回与参数
- 注意:
- 必须先调用
mysql_init
初始化句柄,再调用此函数; - 若
db
为NULL
,连接后需用mysql_select_db
手动切换数据库。
- 必须先调用
3. mysql_close
- 原型:
void mysql_close(MYSQL *mysql);
- 功能:关闭与 MySQL 服务器的连接,释放
MYSQL
结构体占用的内存。 - 注意:所有操作完成后必须调用,否则会导致内存泄漏。
二、SQL 语句执行
这类函数用于向 MySQL 服务器发送 SQL 语句(查询、插入、更新等)并获取执行状态。
1. mysql_query
- 原型:
int mysql_query(MYSQL *mysql, const char *sql);
- 功能:执行 SQL 语句(字符串需以
\0
结尾,即 C 风格字符串)。 - 参数:
mysql
:连接句柄;sql
:要执行的 SQL 语句(如SELECT * FROM student
)。
- 返回值:
- 成功:
0
; - 失败:非
0
(错误信息通过mysql_error
获取)。
- 成功:
- 适用场景:执行常规 SQL 语句(无二进制数据,字符串以
\0
结尾)。
2. mysql_real_query
- 原型:
int mysql_real_query(MYSQL *mysql, const char *sql, unsigned long length);
- 功能:执行 SQL 语句,支持包含二进制数据或
\0
字符的 SQL(需显式指定长度)。 - 参数:
length
:sql
字符串的长度(字节数),解决\0
截断问题。
- 适用场景:SQL 语句中包含二进制数据(如图片、序列化数据)或
\0
字符时(mysql_query
会因\0
截断而失败)。
三、查询结果处理
这类函数用于获取 SELECT
语句的查询结果,解析字段和行数据。
1. mysql_store_result
- 原型:
MYSQL_RES *mysql_store_result(MYSQL *mysql);
- 功能:将查询结果全部加载到客户端内存,适合小结果集(如几十到几千行)。
- 返回值:
- 成功:返回
MYSQL_RES*
结果集句柄; - 失败:返回
NULL
(可通过mysql_field_count
判断是 “无结果” 还是 “错误”)。
- 成功:返回
- 优点:可随机访问结果(如反复调用
mysql_fetch_row
),支持mysql_num_rows
获取总行数。
2. mysql_use_result
- 原型:
MYSQL_RES *mysql_use_result(MYSQL *mysql);
- 功能:初始化一个 “流式结果集”,逐行从服务器获取数据(不加载全部到内存),适合大结果集(如几万行以上)。
- 返回值:与
mysql_store_result
相同。 - 注意:
- 必须按顺序读取所有行(不能跳过或回头读),否则会阻塞服务器;
- 读取期间不能执行其他 SQL 语句(需先读完或调用
mysql_free_result
); - 不支持
mysql_num_rows
(无法提前获取总行数)。
3. mysql_fetch_row
- 原型:
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
- 功能:从结果集中获取一行数据(适用于
mysql_store_result
或mysql_use_result
返回的结果集)。 - 返回值:
- 成功:返回
MYSQL_ROW
类型(本质是char**
,字符串数组,每个元素对应一个字段值); - 失败 / 无更多行:返回
NULL
。
- 成功:返回
- 注意:
- 字段值为
NULL
时,对应数组元素为NULL
(需手动判断); - 数据以字符串形式返回(即使字段是数字,需手动转换为
int
/float
)。
- 字段值为
4. mysql_num_fields
- 原型:
unsigned int mysql_num_fields(MYSQL_RES *result);
- 功能:获取结果集中的字段数(列数)。
5. mysql_fetch_fields
- 原型:
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result);
- 功能:获取结果集中所有字段的元信息(如字段名、类型、长度等)。
- 返回值:返回
MYSQL_FIELD*
数组(长度为mysql_num_fields
的返回值)。 - 示例:打印所有字段名
MYSQL_FIELD *fields = mysql_fetch_fields(result); for (int i = 0; i < mysql_num_fields(result); i++) {printf("%s\t", fields[i].name); // 打印列名 }
6. mysql_free_result
- 原型:
void mysql_free_result(MYSQL_RES *result);
- 功能:释放结果集占用的内存(必须调用,否则内存泄漏)。
四、事务与状态控制
这类函数用于管理事务、设置字符集、获取连接状态等。
1. mysql_autocommit
- 原型:
my_bool mysql_autocommit(MYSQL *mysql, my_bool mode);
- 功能:设置事务自动提交模式。
- 参数:
mode
:1
表示自动提交(默认),0
表示手动提交(需显式调用mysql_commit
)。
2. mysql_commit
- 原型:
my_bool mysql_commit(MYSQL *mysql);
- 功能:提交当前事务(仅当
mysql_autocommit
设为0
时有效)。
3. mysql_rollback
- 原型:
my_bool mysql_rollback(MYSQL *mysql);
- 功能:回滚当前事务(取消未提交的操作)。
4. mysql_set_character_set
- 原型:
int mysql_set_character_set(MYSQL *mysql, const char *csname);
- 功能:设置客户端与服务器通信的字符集(解决中文乱码)。
- 参数:
csname
为字符集名称(推荐utf8mb4
,支持所有中文和 emoji)。
五、错误处理
这类函数用于获取操作失败时的错误信息,便于调试。
1. mysql_errno
- 原型:
unsigned int mysql_errno(MYSQL *mysql);
- 功能:返回最后一次操作的错误代码(
0
表示无错误)。
2. mysql_error
- 原型:
const char *mysql_error(MYSQL *mysql);
- 功能:返回最后一次操作的错误描述字符串(如
Access denied for user
)。 - 示例:
if (mysql_query(conn, sql) != 0) {fprintf(stderr, "错误代码:%u,错误信息:%s\n", mysql_errno(conn), mysql_error(conn)); }
示例一:
以下是使用 MySQL C API 实现常见数据库操作的代码示例,涵盖连接数据库、查询数据、插入数据、更新数据、删除数据等核心场景,并包含详细注释和错误处理。
前提准备
- 确保已安装 MySQL 开发库(
libmysqlclient
),并在编译时链接该库(如 Linux 下用-lmysqlclient
)。 - 假设存在测试表
student
,结构如下:CREATE TABLE student (s_id INT PRIMARY KEY AUTO_INCREMENT, -- 学号(自增)s_name VARCHAR(50) NOT NULL, -- 姓名s_score INT, -- 成绩s_sex CHAR(2) -- 性别 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
示例代码:完整操作集合
#include <stdio.h>
#include <stdlib.h>
#include <mysql.h> // MySQL C API 头文件// 错误处理宏(简化重复代码)
#define CHECK_ERROR(conn, msg) \if (mysql_errno(conn) != 0) { \fprintf(stderr, "[错误] %s: %s(错误码:%u)\n", msg, mysql_error(conn), mysql_errno(conn)); \mysql_close(conn); \return 1; \}// 1. 连接数据库函数
MYSQL* connect_db(const char* host, const char* user, const char* passwd, const char* db_name, unsigned int port) {MYSQL* conn = mysql_init(NULL); // 初始化连接句柄if (conn == NULL) {fprintf(stderr, "[错误] 初始化连接句柄失败(内存不足)\n");return NULL;}// 建立连接if (mysql_real_connect(conn, host, user, passwd, db_name, port, NULL, 0) == NULL) {fprintf(stderr, "[错误] 连接数据库失败:%s(错误码:%u)\n", mysql_error(conn), mysql_errno(conn));mysql_close(conn);return NULL;}// 设置字符集(支持中文)if (mysql_set_character_set(conn, "utf8mb4") != 0) {fprintf(stderr, "[错误] 设置字符集失败:%s\n", mysql_error(conn));mysql_close(conn);return NULL;}printf("数据库连接成功!\n");return conn;
}// 2. 查询数据(SELECT)
void query_data(MYSQL* conn) {const char* sql = "SELECT s_id, s_name, s_score, s_sex FROM student WHERE s_score >= 60";if (mysql_query(conn, sql) != 0) { // 执行查询fprintf(stderr, "[错误] 查询失败:%s\n", mysql_error(conn));return;}// 获取结果集(全部加载到内存)MYSQL_RES* result = mysql_store_result(conn);if (result == NULL) {fprintf(stderr, "[错误] 获取结果集失败:%s\n", mysql_error(conn));return;}// 获取字段数和字段信息int num_fields = mysql_num_fields(result);MYSQL_FIELD* fields = mysql_fetch_fields(result);// 打印表头(字段名)printf("\n===== 查询结果(成绩>=60的学生) =====\n");for (int i = 0; i < num_fields; i++) {printf("%-10s", fields[i].name); // 左对齐,占10个字符}printf("\n");// 遍历行数据MYSQL_ROW row;while ((row = mysql_fetch_row(result)) != NULL) {for (int i = 0; i < num_fields; i++) {// 字段值可能为NULL,用"NULL"表示printf("%-10s", row[i] ? row[i] : "NULL");}printf("\n");}// 释放结果集mysql_free_result(result);printf("====================================\n");
}// 3. 插入数据(INSERT)
void insert_data(MYSQL* conn) {// 插入语句(使用参数化可防注入,此处简化用字符串拼接)const char* sql = "INSERT INTO student (s_name, s_score, s_sex) VALUES ""('张三', 85, '男'), ""('李四', 92, '男'), ""('王五', 78, '女')";if (mysql_query(conn, sql) != 0) { // 执行插入fprintf(stderr, "[错误] 插入失败:%s\n", mysql_error(conn));return;}// 获取插入的行数和最后一条记录的自增IDmy_ulonglong affected_rows = mysql_affected_rows(conn);unsigned long long last_id = mysql_insert_id(conn);printf("\n插入成功!影响行数:%llu,最后插入的ID:%llu\n", affected_rows, last_id);
}// 4. 更新数据(UPDATE)
void update_data(MYSQL* conn) {// 将张三的成绩更新为90const char* sql = "UPDATE student SET s_score = 90 WHERE s_name = '张三'";if (mysql_query(conn, sql) != 0) { // 执行更新fprintf(stderr, "[错误] 更新失败:%s\n", mysql_error(conn));return;}my_ulonglong affected_rows = mysql_affected_rows(conn);printf("\n更新成功!影响行数:%llu\n", affected_rows);
}// 5. 删除数据(DELETE)
void delete_data(MYSQL* conn) {// 删除成绩<60的学生(假设存在)const char* sql = "DELETE FROM student WHERE s_score < 60";if (mysql_query(conn, sql) != 0) { // 执行删除fprintf(stderr, "[错误] 删除失败:%s\n", mysql_error(conn));return;}my_ulonglong affected_rows = mysql_affected_rows(conn);printf("\n删除成功!影响行数:%llu\n", affected_rows);
}int main() {// 数据库连接参数(替换为你的实际信息)const char* host = "localhost";const char* user = "root";const char* passwd = "your_password"; // 你的MySQL密码const char* db_name = "test_db"; // 数据库名unsigned int port = 3306;// 1. 连接数据库MYSQL* conn = connect_db(host, user, passwd, db_name, port);if (conn == NULL) {return 1; // 连接失败,退出}// 2. 执行各种操作insert_data(conn); // 插入数据update_data(conn); // 更新数据query_data(conn); // 查询数据delete_data(conn); // 删除数据(可选)// 3. 关闭连接mysql_close(conn);printf("\n数据库连接已关闭\n");return 0;
}
代码说明
1. 核心函数解析
connect_db
:封装连接逻辑,包括初始化句柄、建立连接、设置字符集,返回连接句柄(MYSQL*
)。query_data
:执行SELECT
语句,获取结果集并打印(包含字段名和行数据),注意处理NULL
值和释放结果集。insert_data
:执行INSERT
语句,通过mysql_affected_rows
获取影响行数,mysql_insert_id
获取自增 ID。update_data
和delete_data
:分别执行UPDATE
和DELETE
,通过mysql_affected_rows
确认操作效果。
2. 编译与运行
- Linux/macOS:
gcc mysql_demo.c -o mysql_demo -lmysqlclient # 编译(链接mysqlclient库) ./mysql_demo # 运行
3. 关键注意事项
- 参数化查询:示例中用字符串拼接 SQL 存在 SQL 注入风险,实际开发需用预处理语句(
mysql_stmt_init
等),参考:// 预处理示例(防注入) MYSQL_STMT* stmt = mysql_stmt_init(conn); const char* sql = "INSERT INTO student (s_name) VALUES (?)"; mysql_stmt_prepare(stmt, sql, strlen(sql)); // 绑定参数...(略)
- 资源释放:
mysql_free_result
(释放结果集)和mysql_close
(关闭连接)必须调用,否则内存泄漏。 - 错误处理:几乎所有 API 操作都需检查返回值,通过
mysql_error
和mysql_errno
调试。
通过以上示例,可掌握 C 语言操作 MySQL 的核心流程,根据实际需求扩展功能(如事务处理、批量操作等)