前面讲的都是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.20
或 libmysqlclient.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;
}
