MySQL常用API

MySQL常用API

在 C 语言中操作 MySQL 数据库依赖于 MySQL 官方提供的 C API (也称为 libmysqlclient),这套 API 包含一系列函数,覆盖从 "初始化连接" 到 "释放资源" 的全流程。以下按操作顺序分类介绍核心函数,包括函数原型、参数、返回值及使用场景:

一、连接初始化与关闭

这类函数用于初始化 MySQL 连接句柄、建立连接及释放资源,是所有操作的基础。

1. mysql_init
  • 原型

    cpp 复制代码
    MYSQL *mysql_init(MYSQL *mysql);
  • 功能 :初始化 MySQL 连接句柄(MYSQL 结构体),分配内存并设置默认属性。

  • 参数

    • mysql:若为 NULL,函数会自动分配新的 MYSQL 结构体;若传入已存在的句柄,会重置该句柄(清空之前的连接信息)。
  • 返回值

    • 成功:返回初始化后的 MYSQL* 句柄;
    • 失败:返回 NULL(通常因内存不足)。
  • 示例

    cpp 复制代码
    MYSQL *conn = mysql_init(NULL);  // 初始化新句柄
    if (conn == NULL) {
        fprintf(stderr, "初始化失败:内存不足\n");
    }
2. mysql_real_connect
  • 原型

    cpp 复制代码
    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 初始化句柄,再调用此函数;
    • dbNULL,连接后需用 mysql_select_db 手动切换数据库。
3. mysql_close
  • 原型

    cpp 复制代码
    void mysql_close(MYSQL *mysql);
  • 功能 :关闭与 MySQL 服务器的连接,释放 MYSQL 结构体占用的内存。

  • 注意:所有操作完成后必须调用,否则会导致内存泄漏。

二、SQL 语句执行

这类函数用于向 MySQL 服务器发送 SQL 语句(查询、插入、更新等)并获取执行状态。

1. mysql_query
  • 原型

    cpp 复制代码
    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
  • 原型

    cpp 复制代码
    int mysql_real_query(MYSQL *mysql, const char *sql, unsigned long length);
  • 功能 :执行 SQL 语句,支持包含二进制数据或 \0 字符的 SQL(需显式指定长度)。

  • 参数

    • lengthsql 字符串的长度(字节数),解决 \0 截断问题。
  • 适用场景 :SQL 语句中包含二进制数据(如图片、序列化数据)或 \0 字符时(mysql_query 会因 \0 截断而失败)。

三、查询结果处理

这类函数用于获取 SELECT 语句的查询结果,解析字段和行数据。

1. mysql_store_result
  • 原型

    cpp 复制代码
    MYSQL_RES *mysql_store_result(MYSQL *mysql);
  • 功能 :将查询结果全部加载到客户端内存,适合小结果集(如几十到几千行)。

  • 返回值

    • 成功:返回 MYSQL_RES* 结果集句柄;
    • 失败:返回 NULL(可通过 mysql_field_count 判断是 "无结果" 还是 "错误")。
  • 优点 :可随机访问结果(如反复调用 mysql_fetch_row),支持 mysql_num_rows 获取总行数。

2. mysql_use_result
  • 原型

    cpp 复制代码
    MYSQL_RES *mysql_use_result(MYSQL *mysql);
  • 功能 :初始化一个 "流式结果集",逐行从服务器获取数据(不加载全部到内存),适合大结果集(如几万行以上)。

  • 返回值 :与 mysql_store_result 相同。

  • 注意

    • 必须按顺序读取所有行(不能跳过或回头读),否则会阻塞服务器;
    • 读取期间不能执行其他 SQL 语句(需先读完或调用 mysql_free_result);
    • 不支持 mysql_num_rows(无法提前获取总行数)。
3. mysql_fetch_row
  • 原型

    cpp 复制代码
    MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
  • 功能 :从结果集中获取一行数据(适用于 mysql_store_resultmysql_use_result 返回的结果集)。

  • 返回值

    • 成功:返回 MYSQL_ROW 类型(本质是 char**,字符串数组,每个元素对应一个字段值);
    • 失败 / 无更多行:返回 NULL
  • 注意

    • 字段值为 NULL 时,对应数组元素为 NULL(需手动判断);
    • 数据以字符串形式返回(即使字段是数字,需手动转换为 int/float)。
4. mysql_num_fields
  • 原型

    cpp 复制代码
    unsigned int mysql_num_fields(MYSQL_RES *result);
  • 功能:获取结果集中的字段数(列数)。

5. mysql_fetch_fields
  • 原型

    cpp 复制代码
    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result);
  • 功能:获取结果集中所有字段的元信息(如字段名、类型、长度等)。

  • 返回值 :返回 MYSQL_FIELD* 数组(长度为 mysql_num_fields 的返回值)。

  • 示例 :打印所有字段名

    cpp 复制代码
    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
  • 原型

    cpp 复制代码
    void mysql_free_result(MYSQL_RES *result);
  • 功能:释放结果集占用的内存(必须调用,否则内存泄漏)。

四、事务与状态控制

这类函数用于管理事务、设置字符集、获取连接状态等。

1. mysql_autocommit
  • 原型

    cpp 复制代码
    my_bool mysql_autocommit(MYSQL *mysql, my_bool mode);
  • 功能:设置事务自动提交模式。

  • 参数

    • mode1 表示自动提交(默认),0 表示手动提交(需显式调用 mysql_commit)。
2. mysql_commit
  • 原型

    cpp 复制代码
    my_bool mysql_commit(MYSQL *mysql);
  • 功能 :提交当前事务(仅当 mysql_autocommit 设为 0 时有效)。

3. mysql_rollback
  • 原型

    cpp 复制代码
    my_bool mysql_rollback(MYSQL *mysql);
  • 功能:回滚当前事务(取消未提交的操作)。

4. mysql_set_character_set
  • 原型

    cpp 复制代码
    int mysql_set_character_set(MYSQL *mysql, const char *csname);
  • 功能:设置客户端与服务器通信的字符集(解决中文乱码)。

  • 参数csname 为字符集名称(推荐 utf8mb4,支持所有中文和 emoji)。

五、错误处理

这类函数用于获取操作失败时的错误信息,便于调试。

1. mysql_errno
  • 原型

    cpp 复制代码
    unsigned int mysql_errno(MYSQL *mysql);
  • 功能 :返回最后一次操作的错误代码(0 表示无错误)。

2. mysql_error
  • 原型

    cpp 复制代码
    const char *mysql_error(MYSQL *mysql);
  • 功能 :返回最后一次操作的错误描述字符串(如 Access denied for user)。

  • 示例

    cpp 复制代码
    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,结构如下:

    sql 复制代码
    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;

示例代码:完整操作集合

cpp 复制代码
#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;
    }

    // 获取插入的行数和最后一条记录的自增ID
    my_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) {
    // 将张三的成绩更新为90
    const 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_datadelete_data :分别执行 UPDATEDELETE,通过 mysql_affected_rows 确认操作效果。
2. 编译与运行
  • Linux/macOS

    bash 复制代码
    gcc mysql_demo.c -o mysql_demo -lmysqlclient  # 编译(链接mysqlclient库)
    ./mysql_demo                                  # 运行
3. 关键注意事项
  • 参数化查询 :示例中用字符串拼接 SQL 存在 SQL 注入风险,实际开发需用预处理语句(mysql_stmt_init 等),参考:

    cpp 复制代码
    // 预处理示例(防注入)
    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_errormysql_errno 调试。

通过以上示例,可掌握 C 语言操作 MySQL 的核心流程,根据实际需求扩展功能(如事务处理、批量操作等)

相关推荐
fanstuck4 小时前
开源项目重构我们应该怎么做-以 SQL 血缘系统开源项目为例
数据库·sql·重构·数据挖掘·数据治理
weixin_307779134 小时前
C#实现MySQL→Clickhouse建表语句转换工具
开发语言·数据库·算法·c#·自动化
hrrrrb6 小时前
【Spring Security】Spring Security 概念
java·数据库·spring
心止水j6 小时前
spark
javascript·数据库·spark
xujiangyan_7 小时前
Redis详解
数据库·redis·缓存
Y编程小白10 小时前
PostgreSQL在Linux中的部署和安装教程
数据库·postgresql
TiAmo zhang12 小时前
SQL Server 2019实验 │ 数据库和表的创建、修改与删除
数据库·oracle
闲人编程13 小时前
从多个数据源(CSV, Excel, SQL)自动整合数据
python·mysql·数据分析·csv·存储·数据源·codecapsule
disanleya13 小时前
MySQL默认密码不安全?如何首次登录并强化?
数据库·mysql·安全