这篇会介绍如何使用 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。 |
| $port | |
| $user_name | 数据库连接账户用户名及密码,详细请参见 创建账号。 |
| $password | |
| $database_name | 需要访问的数据库名称。 |
注意:连接数据库的用户需要拥有该数据库的 CREATE、INSERT、DROP 和 SELECT 权限。
示例如下:
mysql -h192.168.1.100 -P3306 -utest_user -p****** -Dtest_db
四、步骤二:安装 MySQL Connector/C 驱动
根据你的操作系统选择相应的安装命令:
## 在 Ubuntu/Debian 系统上请使用下面的代码进行安装:sudo apt-get updatesudo 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/Debiansudo 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);
十六、参考资料
MySQL C API 产品文档