16--MySQL使用C语言进行连接

前面讲的都是MySQL命令行的使用,我们后面还要将MySQL与C等其他语言建立连接,才能更好的使用MySQL

前言

要使用 C 语言连接 mysql ,需要使用 mysql 官网提供的库,大家可以去 官网 下载对应的库
MySQL :: MySQL Community Downloads

MySQL开发包

安装

作用

组件类型 示例文件/工具 作用
头文件 mysql.h, errmsg.h 定义API函数、错误码、数据结构(如MYSQL连接句柄)。
库文件 libmysqlclient.so (动态库) 提供连接、查询、事务等功能的实现。
libmysqlclient.a (静态库) 静态链接时使用(较少用,因动态库更灵活)。
配置工具 mysql_config 输出编译选项(如-I/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient)。
示例代码 client_test.c(部分包提供) 演示如何使用API进行基本操作(如连接、查询)。

查看我们下载的库和头文件

include 包含所有的方法声明, lib 包含所有的方法实现(打包成库)

与C语言建立MySQL数据库连接的动态库文件是 libmysqlclient.so.20libmysqlclient.so.18(具体取决于MySQL客户端版本)

20对应的是MySQL8.0+版本

18对应的是MySQL5.7以前的版本

补充知识

1.查看MySQL版本
复制代码
mysql --version
2.库的位置

我们上面演示的时候可以看到根目录和/usr目录下都有lib和lib64两个目录,有什么区别吗

特性 /lib(/lib64 ) /usr/lib(/usr/lib64)
用途 系统核心库(启动依赖) 应用程序库(第三方软件)
权限 严格(仅root) 较宽松(root或安装者)
内容示例 libc.so.6, ld-linux.so.2 libmysqlclient.so, libssl.so
是否可删除 ❌ 绝对不可删除(系统崩溃风险) ✅ 可删除(需确认无程序依赖)
FHS标准分类 基础系统(/层级) 应用程序(/usr层级)
3.头文件的位置

include是不会放在根目录下的,因为不是系统启动所必须的,这个目录放在 /usr 目录下

/usr/include

上面的MySQL头文件是在默认路径下,如果在该路径下查找不到,可以使用动态查询

复制代码
mysql_config --include

尝试链接mysql client

通过 mysql_get_client_info() 函数,来验证我们的引入是否成功

这里我们可以看到成功调用了mysql_get_client_info() 函数,说明引入MySQL成功了

至此,MySQL库的引入结束了,接下来是熟悉接口

mysql接口操作

mysql_init()

初始化函数,要使用mysql,就必须要初始化

语法

复制代码
MYSQL* mysql_init(MYSQL *mysql);

--例如
MYSQL* my =mysql_init(NULL);

mysql_real_connect()

链接数据库函数,初始化之后,必须先链接数据库

复制代码
MYSQL *mysql_real_connect(
  MYSQL *mysql,          // 初始化后的连接句柄
  const char *host,      // 服务器主机名/IP
  const char *user,      // 用户名
  const char *passwd,    // 密码
  const char *db,        // 默认数据库名
  unsigned int port,     // 端口号
  const char *unix_socket, // Unix套接字路径
  unsigned long client_flag // 客户端标志位
);

第一个参数 MYSQL 是 C api 中一个非常重要的变量( mysql_init 的返回值),里面内存非常丰富,有 port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods 的结构体变量,该变量 里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。
mysql_real_connect 函数中各参数,基本都是顾名思意。

解决中文乱码问题

建立好链接之后,获取英文没有问题,如果获取中文是乱码:
设置链接的默认字符集是utf8,原始默认是latin1

复制代码
mysql_set_character_set(myfd, "utf8");

mysql_query()

下发mysql命令函数

复制代码
int mysql_query(MYSQL *mysql, const char *q);

第二个参数是要执行的sql指令,如select * from table

获取数据结果

mysql_store_result()

sql 执行完以后,如果是查询语句,我们当然还要读取数据,如果 update , insert 等语句,那么就看下操 作成功与否即可。我们来看看如何获取查询结果: 如果mysql_query 返回成功,那么我们就通过 mysql_store_result这个函数来读取结果。

复制代码
MYSQL_RES *mysql_store_result(MYSQL *mysql);

该函数会调用 MYSQL 变量中的 st_mysql_methods 中的 read_rows 函数指针来获取查询的结果。同时该 函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数 malloc 了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result), 不然是肯定会造成内存泄漏的。 执行完mysql_store_result 以后,其实数据都已经在 MYSQL_RES 变量中了,所以这个函数实际上就是把结果缓存到内存中

mysql_use_result()

复制代码
MYSQL_RES *mysql_use_result(MYSQL *mysql);

逐行获取结果集,比较节省内存的方法

查询结果集元信息

mysql_num_field()

复制代码
unsigned int mysql_num_fields(MYSQL_RES *result);

返回结果集的列数,用来遍历结果集时确定循环次数

mysql_field_name()

复制代码
const char *mysql_field_name(MYSQL_RES *result, unsigned int field_index);

返回指定列的名称

遍历结果集

mysql_fetch_row()

复制代码
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

返回结果集的下一行数据指针(MYSQL_ROW类型,即字符串数组)

配合mysql_store_result():无更多行时返回NULL

配合mysql_use_result():无更多行或出错时返回NULL(需通过mysql_error()区分)

复制代码
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
    for (int i = 0; i < mysql_num_fields(res); i++) {
        printf("%s ", row[i] ? row[i] : "NULL"); // 处理NULL值
    }
}

row变量保存mysql_fetch_row返回的数据指针

外层循环 :通过mysql_fetch_row()逐行获取结果集数据,当所有行处理完毕时返回NULL终止循环

内层循环 :遍历当前行的每个字段,mysql_num_fields(res)动态获取结果集的列数

从逻辑上来看,结果集是可以看成一个数组的

  • 行(Row):每一行代表一条数据库记录。
  • 列(Column/Field):每一列代表记录中的一个字段。

错误信息函数

mysql_errno()

获取最近一次MySQL操作产生的错误码(整数)

mysql_error()

获取最近一次MySQL操作的错误描述字符串。

关闭MySQL函数

mysql_close()

复制代码
mysql_close(MYSQL *sock); 

实例

复制代码
#include <stdio.h>
#include <mysql.h>

int main() {


    MYSQL* conn = NULL;     // 数据库句柄
    MYSQL_RES* res = NULL;  // 结果集指针
    MYSQL_ROW row = NULL;   // 行数据指针(修正变量名)

    // 1. 初始化连接句柄
    conn = mysql_init(NULL);
    if (!conn) {
        fprintf(stderr, "初始化失败: %s\n", mysql_error(conn));
        return 1;
    }
    // 2. 解决中文乱码问题
    mysql_set_character_set(conn, "utf8");

    // 3. 建立数据库连接
    const char *host = "localhost";
    const char *user = "shenyu";
    const char *passwd = "Mysql@6666";
    const char *db = "test";
    unsigned int port = 3306;

    if (!mysql_real_connect(conn, host, user, passwd, db, port, NULL, 0)) {
        fprintf(stderr, "连接失败: %s\n", mysql_error(conn));
        mysql_close(conn);
        return 1;
    }

    // 4. 执行SQL查询
    const char *query = "SELECT * FROM stu";
    if (mysql_query(conn, query)) {
        fprintf(stderr, "查询失败: %s\n", mysql_error(conn));
        mysql_close(conn);
        return 1;
    }

    // 5. 获取并处理结果集
    res = mysql_store_result(conn);
    if (!res) {
        fprintf(stderr, "结果集获取失败: %s\n", mysql_error(conn));
        mysql_close(conn);
        return 1;
    }

    // 打印列名
    int num_fields = mysql_num_fields(res);
    int i;  // 将循环变量移到外部
    for (i = 0; i < num_fields; i++) {
        MYSQL_FIELD *field = mysql_fetch_field_direct(res, i);
        printf("%-15s", field->name);
    }
    printf("\n");

    // 遍历行数据
    while ((row = mysql_fetch_row(res))) {
        unsigned long *lengths = mysql_fetch_lengths(res);
        for (i = 0; i < num_fields; i++) {  // 复用外部变量i
            if (row[i]) 
                printf("%-15.*s", (int)lengths[i], row[i]);
            else
                printf("%-15s", "NULL");
        }
        printf("\n");
    }

    // 6. 释放资源
    mysql_free_result(res);
    mysql_close(conn);
    return 0;
}
相关推荐
zhangfeng11332 小时前
在Cytoscape中安装GeneMANIA插件后相关数据(包括网络数据、物种数据库等)的存储位置,安装目录位置
数据库
Full Stack Developme3 小时前
PostgreSql FDW 与 DBLINK 区别
数据库·postgresql
数字化顾问3 小时前
从索引失效到毫秒级响应——SQL 优化实战案例:从慢查询到高性能的完整指南之电商大促篇
java·开发语言·数据库
小园子的小菜3 小时前
深入剖析 MySQL 中 binlog 与 redolog:区别、联系及在数据更新中的作用
数据库·mysql
李宥小哥5 小时前
C#基础07-类与对象
服务器·数据库·c#
樱木...5 小时前
MySQL 8.0 新特性之原子 DDL
数据库·mysql
1688red5 小时前
MySQL连接时提示ERROR 2002 (HY000)解决方案
数据库·mysql
代码小菜鸡6666 小时前
10.2 刷题知识点总结(1) ---- 正则表达式
数据库
lagelangri6666 小时前
数据库连接池以及HikariCP使用
数据库·oracle