C

最近更新时间:2026-02-05 11:01:13

我的收藏
MySQL Connector/C 通常被称为 MySQL C API,它提供了一组 C 语言的函数和数据结构,允许开发人员使用 C/C++ 语言来连接、查询和管理数据库。这个 API 允许开发人员直接在其 C/C++ 应用程序中使用兼容 MySQL 协议的数据库。
本文将介绍如何使用 MySQL Connector/C (libmysqlclient) 驱动和 TDSQL Boundless 数据库构建一个应用程序,实现创建表、插入数据和查询数据等基本操作。

前提条件

在安装使用 MySQL Connector/C (libmysqlclient) 前请确保设置了基本的数据库开发环境,要求如下:
GCC 版本为3.4.6及以上,推荐使用4.8.5版本。
CMake 版本为2.8.12及以上。
您已部署 TDSQL Boundless 数据库并创建了相应的数据库实例。

操作步骤

1. 获取 TDSQL Boundless 数据库连接信息。
2. 安装 MySQL Connector/C 驱动。
3. 编写应用程序。
4. 编译应用程序。
5. 运行应用程序。

步骤一:获取数据库连接串

mysql -h$host -P$port -u$user_name -p$password -D$database_name
参数说明:
参数
说明
$host
TDSQL Boundless 数据库连接 IP 地址或域名及端口(默认为 3306)。
OLTP 类访问地址:对等节点 VIP 地址及端口号可登录控制台,通过实例详情页面,在基本信息区域,内网地址字段获取对等节点 VIP,内网端口字段获取对等节点 Port。
OLAP 类访问地址:列存节点 VIP 地址及端口号可登录控制台,通过实例详情页面,在实例架构图区域,Columnar Node 中查看对应的 VIPPort 信息。
$port
$user_name
数据库连接账户用户名及密码,详细请参见 创建账号
$password
$database_name
需要访问的数据库名称。
注意:
连接数据库的用户需要拥有该数据库的 CREATEINSERTDROPSELECT 权限。
示例如下:
mysql -h192.168.1.100 -P3306 -utest_user -p****** -Dtest_db

步骤二:安装 MySQL Connector/C 驱动

根据您的操作系统选择相应的安装命令:
## 在 Ubuntu/Debian 系统上请使用下面的代码进行安装:
sudo apt-get update
sudo apt-get install libmysqlclient-dev

## 在 CentOS/RHEL 系统上请使用下面的代码进行安装:
sudo yum install mysql-devel

## 确认是否安装成功
mysql_config --version
如果安装成功,mysql_config --version 命令将输出已安装的 MySQL 客户端库版本号。

步骤三:编写应用程序

打开你的文本编辑器,在文本编辑器中编辑示例 test.c 文件并保存,代码如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

int main() {
MYSQL *conn = mysql_init(NULL); // 初始化 MySQL 连接

if (conn == NULL) {
fprintf(stderr, "mysql_init() failed\\n");
return 1;
}

// 连接到 TDSQL Boundless 数据库服务器
// 请将以下参数替换为实际的连接信息
if (mysql_real_connect(conn, "host", "user", "passwd", "db", 3306, NULL, 0) == NULL) {
fprintf(stderr, "mysql_real_connect() failed: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

printf("成功连接到 TDSQL Boundless 数据库!\\n");

// 设置字符集为 utf8mb4
if (mysql_set_character_set(conn, "utf8mb4") != 0) {
fprintf(stderr, "设置字符集失败: %s\\n", mysql_error(conn));
}

// 创建用户表
if (mysql_query(conn, "CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT, name VARCHAR(255), email VARCHAR(255), PRIMARY KEY(id))") != 0) {
fprintf(stderr, "创建表失败: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
printf("表创建成功!\\n");

// 插入数据
if (mysql_query(conn, "INSERT INTO users (name, email) VALUES ('小明', 'xiaoming@example.com')") != 0) {
fprintf(stderr, "插入数据失败: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}
printf("数据插入成功!\\n");

// 查询数据
if (mysql_query(conn, "SELECT * FROM users") == 0) {
MYSQL_RES *result = mysql_store_result(conn);
if (result != NULL) {
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
printf("\\n查询结果:\\n");
printf("----------------------------------------\\n");
while ((row = mysql_fetch_row(result))) {
for (int i = 0; i < num_fields; i++) {
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\\n");
}
printf("----------------------------------------\\n");
printf("共 %lu 条记录\\n", (unsigned long)mysql_num_rows(result));
mysql_free_result(result);
} else {
fprintf(stderr, "获取结果集失败: %s\\n", mysql_error(conn));
}
} else {
fprintf(stderr, "查询数据失败: %s\\n", mysql_error(conn));
}

mysql_close(conn); // 关闭连接
printf("数据库连接已关闭。\\n");
return 0;
}
根据 步骤一:获取数据库连接信息 中的信息修改项目文件 test.c 中的数据库连接信息。
在 Linux 环境下,可以使用 vi test.c 或者 vim test.c 命令编辑 test.c 文件,修改文件中的数据库连接信息,确保与实际情况相符。
test.c 文件中的数据库连接信息示例如下:
// 这部分连接信息需要修改为你所获取到连接串的真实信息,示例如下
if (mysql_real_connect(conn, "192.168.1.100", "test_user", "your_password", "test_db", 3306, NULL, 0) == NULL) {
fprintf(stderr, "mysql_real_connect() failed: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

步骤四:编译应用程序

代码编辑完成后,可以通过如下命令进行编译。
gcc -o test test.c `mysql_config --cflags --libs`
或者手动指定头文件和库路径:
gcc -o test test.c -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient
编译成功后,会生成可执行文件 test

步骤五:运行应用程序

通过如下命令运行应用程序。
./test
输出结果如下,说明数据库连接成功,示例语句正确执行:
成功连接到 TDSQL Boundless 数据库!
表创建成功!
数据插入成功!

查询结果:
----------------------------------------
1 小明 xiaoming@example.com
----------------------------------------
1 条记录

测试表已清理。
数据库连接已关闭。

更多示例

示例1:使用预处理语句插入数据

预处理语句可以有效防止 SQL 注入,并提高重复执行相同 SQL 语句的性能。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>

int main() {
MYSQL *conn = mysql_init(NULL);
MYSQL_STMT *stmt;
MYSQL_BIND bind[2];
char name[64] = "张三";
char email[128] = "zhangsan@example.com";
unsigned long name_length;
unsigned long email_length;

if (conn == NULL) {
fprintf(stderr, "mysql_init() failed\\n");
return 1;
}

// 连接到 TDSQL Boundless 数据库
if (mysql_real_connect(conn, "host", "user", "passwd", "db", 3306, NULL, 0) == NULL) {
fprintf(stderr, "mysql_real_connect() failed: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

// 设置字符集
mysql_set_character_set(conn, "utf8mb4");

// 确保表存在
mysql_query(conn, "CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT, name VARCHAR(255), email VARCHAR(255), PRIMARY KEY(id))");

// 初始化预处理语句
stmt = mysql_stmt_init(conn);
if (stmt == NULL) {
fprintf(stderr, "mysql_stmt_init() failed\\n");
mysql_close(conn);
return 1;
}

// 准备 SQL 语句
const char *sql = "INSERT INTO users (name, email) VALUES (?, ?)";
if (mysql_stmt_prepare(stmt, sql, strlen(sql))) {
fprintf(stderr, "mysql_stmt_prepare() failed: %s\\n", mysql_stmt_error(stmt));
mysql_stmt_close(stmt);
mysql_close(conn);
return 1;
}

// 绑定参数
memset(bind, 0, sizeof(bind));

// 参数 1: name
name_length = strlen(name);
bind[0].buffer_type = MYSQL_TYPE_STRING;
bind[0].buffer = name;
bind[0].buffer_length = sizeof(name);
bind[0].length = &name_length;

// 参数 2: email
email_length = strlen(email);
bind[1].buffer_type = MYSQL_TYPE_STRING;
bind[1].buffer = email;
bind[1].buffer_length = sizeof(email);
bind[1].length = &email_length;

if (mysql_stmt_bind_param(stmt, bind)) {
fprintf(stderr, "mysql_stmt_bind_param() failed: %s\\n", mysql_stmt_error(stmt));
mysql_stmt_close(stmt);
mysql_close(conn);
return 1;
}

// 执行预处理语句
if (mysql_stmt_execute(stmt)) {
fprintf(stderr, "mysql_stmt_execute() failed: %s\\n", mysql_stmt_error(stmt));
mysql_stmt_close(stmt);
mysql_close(conn);
return 1;
}

printf("预处理语句执行成功!插入 ID: %lu\\n", (unsigned long)mysql_stmt_insert_id(stmt));

mysql_stmt_close(stmt);
mysql_close(conn);
return 0;
}

示例2:事务处理

事务可以确保一组数据库操作要么全部成功,要么全部失败。
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

int main() {
MYSQL *conn = mysql_init(NULL);
int success = 1;

if (conn == NULL) {
fprintf(stderr, "mysql_init() failed\\n");
return 1;
}

// 连接到 TDSQL Boundless 数据库
if (mysql_real_connect(conn, "host", "user", "passwd", "db", 3306, NULL, 0) == NULL) {
fprintf(stderr, "mysql_real_connect() failed: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

mysql_set_character_set(conn, "utf8mb4");

// 关闭自动提交,开始事务
if (mysql_autocommit(conn, 0)) {
fprintf(stderr, "关闭自动提交失败: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

printf("事务开始...\\n");

// 执行第一条 SQL
if (mysql_query(conn, "UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")) {
fprintf(stderr, "SQL 1 执行失败: %s\\n", mysql_error(conn));
success = 0;
}

// 执行第二条 SQL
if (success && mysql_query(conn, "UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")) {
fprintf(stderr, "SQL 2 执行失败: %s\\n", mysql_error(conn));
success = 0;
}

if (success) {
// 提交事务
if (mysql_commit(conn)) {
fprintf(stderr, "提交事务失败: %s\\n", mysql_error(conn));
} else {
printf("事务提交成功!\\n");
}
} else {
// 回滚事务
if (mysql_rollback(conn)) {
fprintf(stderr, "回滚事务失败: %s\\n", mysql_error(conn));
} else {
printf("事务已回滚\\n");
}
}

// 恢复自动提交
mysql_autocommit(conn, 1);

mysql_close(conn);
return 0;
}

示例3:批量查询与结果遍历

#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

int main() {
MYSQL *conn = mysql_init(NULL);
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *fields;
unsigned int num_fields;
unsigned int i;

if (conn == NULL) {
fprintf(stderr, "mysql_init() failed\\n");
return 1;
}

// 连接到 TDSQL Boundless 数据库
if (mysql_real_connect(conn, "host", "user", "passwd", "db", 3306, NULL, 0) == NULL) {
fprintf(stderr, "mysql_real_connect() failed: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

mysql_set_character_set(conn, "utf8mb4");

// 执行查询
if (mysql_query(conn, "SELECT id, name, email FROM users ORDER BY id DESC LIMIT 100")) {
fprintf(stderr, "查询失败: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

// 获取结果集
result = mysql_store_result(conn);
if (result == NULL) {
fprintf(stderr, "获取结果集失败: %s\\n", mysql_error(conn));
mysql_close(conn);
return 1;
}

// 获取字段数量和字段信息
num_fields = mysql_num_fields(result);
fields = mysql_fetch_fields(result);

// 打印列名
printf("\\n");
for (i = 0; i < num_fields; i++) {
printf("%-20s", fields[i].name);
}
printf("\\n");
// 打印分隔线
for (i = 0; i < num_fields; i++) {
printf("--------------------");
}
printf("\\n");

// 遍历结果集
while ((row = mysql_fetch_row(result)) != NULL) {
for (i = 0; i < num_fields; i++) {
printf("%-20s", row[i] ? row[i] : "NULL");
}
printf("\\n");
}

printf("\\n共 %lu 行数据\\n", (unsigned long)mysql_num_rows(result));

// 释放结果集
mysql_free_result(result);

mysql_close(conn);
return 0;
}

常用 API 参考

函数
说明
mysql_init()
初始化 MySQL 连接句柄
mysql_real_connect()
连接到数据库服务器
mysql_close()
关闭数据库连接
mysql_query()
执行 SQL 语句
mysql_store_result()
获取完整结果集
mysql_use_result()
逐行获取结果集
mysql_fetch_row()
获取下一行数据
mysql_num_rows()
获取结果集行数
mysql_num_fields()
获取结果集列数
mysql_fetch_fields()
获取字段信息
mysql_affected_rows()
获取受影响的行数
mysql_free_result()
释放结果集
mysql_error()
获取错误信息
mysql_errno()
获取错误码
mysql_set_character_set()
设置字符集
mysql_autocommit()
设置自动提交模式
mysql_commit()
提交事务
mysql_rollback()
回滚事务
mysql_stmt_init()
初始化预处理语句
mysql_stmt_prepare()
准备预处理语句
mysql_stmt_bind_param()
绑定预处理语句参数
mysql_stmt_execute()
执行预处理语句
mysql_stmt_close()
关闭预处理语句

常见问题

1. 编译时找不到 mysql.h 头文件

问题fatal error: mysql/mysql.h: No such file or directory
解决方案:确保已安装 MySQL 开发库,并使用正确的编译参数:
# 安装开发库
sudo apt-get install libmysqlclient-dev # Ubuntu/Debian
sudo yum install mysql-devel # CentOS/RHEL

# 使用 mysql_config 获取正确的编译参数
gcc -o test test.c `mysql_config --cflags --libs`

2. 运行时找不到 libmysqlclient.so

问题error while loading shared libraries: libmysqlclient.so
解决方案
# 方法1:添加库路径到环境变量
export LD_LIBRARY_PATH=/usr/lib/mysql:$LD_LIBRARY_PATH

# 方法2:更新动态链接库缓存
sudo ldconfig

3. 中文显示乱码

问题:查询结果中文显示为乱码
解决方案:连接后设置字符集为 utf8mb4
mysql_set_character_set(conn, "utf8mb4");

4. 连接超时

问题:连接数据库时超时
解决方案:在连接前设置超时参数:
unsigned int timeout = 30;
mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);

参考资料