MySQL C API的使用

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_;         // 记录结构体

};
相关推荐
夏炎正好眠4 小时前
mysql练习
数据库·mysql
驜鸈6 小时前
MySQL 的EXPLAIN 计划 type 字段详细说明
android·数据库·mysql
嗨起飞了7 小时前
MySQL入门手册
数据库·mysql
程序员的世界你不懂8 小时前
Mysql配置文件My.cnf(my.ini)配置参数说明
数据库·mysql·百度·新浪微博
ChinaRainbowSea8 小时前
MySQL 索引的数据结构(详细说明)
java·数据结构·数据库·后端·mysql
追风赶月、8 小时前
【MySQL】事务(隔离性、MVCC)
数据库·mysql
Lemon_man_9 小时前
基于Django创建一个WEB后端框架(DjangoRestFramework+MySQL)流程
python·mysql·django
A仔不会笑11 小时前
MySQL面试篇——性能优化
java·数据库·mysql·面试·性能优化
考虑考虑12 小时前
MySQL中的DATE_FORMAT时间函数
数据库·后端·mysql
杭州刘同学12 小时前
autogen studio如何修改数据库为mysql
mysql·autogen