当前位置: 首页 > news >正文

从零入门:C 语言操作 MySQL 数据库的完整指南

C 语言与 MySQL 数据库交互全解析:从连接到防注入

在程序开发中,数据存储是核心环节之一。目前主流的数据永久性存储方式有文件和数据库,而数据库凭借存储量大、管理便捷、检索速度快等优势,成为多数应用的首选。数据库本质也是一种文件,其背后的 DBMS(数据库管理系统)负责对文件进行控制,让应用程序能便捷地使用存储在数据库表中的数据,这就是软件与数据库的交互。每种编程语言都有与 DBMS 交互的技术,今天我们就来深入探讨 C 语言与 MySQL 数据库的交互方法,助你掌握从连接到防注入的全流程。

一、C 语言与 MySQL 交互流程

要实现 C 语言与 MySQL 的交互,需遵循以下关键步骤,为后续的数据操作打下基础。

1. 选择 DBMS

我们明确选择 MySQL 作为本次交互的 DBMS,它是一款开源且功能强大的关系型数据库管理系统,在工业界应用广泛。

2. 安装 MySQL 编程环境

要让 C 语言程序能访问 MySQL 数据库,必须安装 MySQL 官方提供的依赖库 ——libmysqlclient-dev。该库需安装在 MySQL 所在的服务器上,且建议在 Linux 系统中操作,安装指令如下:

bash

sudo apt-get install libmysqlclient-dev

这个库为 C 语言程序与 MySQL 数据库的对接提供了必要的支持,是两者交互的桥梁。

3. 在 C 程序中添加数据库环境配置

完成库的安装后,需要在 C 程序中进行数据库环境配置,主要包含两部分:

  • 连接初始化指针配置:这一步是为了初始化一个用于与 MySQL 数据库建立连接的指针,后续的数据库操作都将基于这个指针展开。
  • 连接地址信息配置:需配置连接 MySQL 数据库所需的关键信息,包括主机地址(如localhost)、端口号(MySQL 默认端口为 3306)、用户名(如 root)、密码以及要操作的数据库名称。这些信息是确保 C 程序能准确找到并连接到目标数据库的关键。

二、C 语言实现数据库插入、删除、修改操作

插入、删除、修改这三类操作的实现步骤大体相同,核心区别在于所使用的 SQL 语句不同。下面为你详细介绍其通用执行流程,并结合具体示例说明。

1. 通用执行流程

  • 步骤 1:定义操作数据
    根据数据库表的结构,定义相应的结构体或变量来存储要操作的数据。例如,若操作的是用户表(包含用户名、密码字段),可定义一个用户结构体:

c

typedef struct {char username[50];char password[50];
} User;
  • 步骤 2:定义 SQL 语句
    将定义好的数据与对应的 SQL 语句结合起来。以插入操作为例,SQL 语句大致格式为INSERT INTO 表名 (字段1, 字段2) VALUES (值1, 值2);,我们需要将结构体或变量中的数据填充到 SQL 语句中。
  • 步骤 3:执行 SQL 语句
    使用mysql_query函数执行构建好的 SQL 语句,该函数接收两个参数:连接指针和 SQL 语句字符串。函数返回 0 表示执行成功,非 0 则表示执行失败。示例代码如下:

c

if (mysql_query(conn, sql_str) != 0) {printf("SQL执行失败:%s\n", mysql_error(conn));// 执行失败后的处理逻辑
} else {printf("SQL执行成功\n");// 执行成功后的处理逻辑
}
  • 步骤 4:根据执行结果判断状态
    根据mysql_query函数的返回值,判断 SQL 语句是否执行成功,并进行相应的处理。若执行失败,可通过mysql_error函数获取错误信息,便于排查问题。

2. 具体操作示例

  • 插入操作示例
    假设我们有一个用户表users,包含u_name(用户名)和u_pwd(密码)两个字段,插入一条用户数据的代码如下:

c

User user = {"test_user", "test_pwd"};
char sql_str[200];
sprintf(sql_str, "INSERT INTO users (u_name, u_pwd) VALUES ('%s', '%s');", user.username, user.password);
if (mysql_query(conn, sql_str) != 0) {printf("插入数据失败:%s\n", mysql_error(conn));
} else {printf("插入数据成功\n");
}
  • 删除操作示例
    删除用户名为test_user的用户数据,代码如下:

c

char sql_str[200];
sprintf(sql_str, "DELETE FROM users WHERE u_name = '%s';", "test_user");
if (mysql_query(conn, sql_str) != 0) {printf("删除数据失败:%s\n", mysql_error(conn));
} else {printf("删除数据成功\n");
}
  • 修改操作示例
    将用户名test_user的密码修改为new_test_pwd,代码如下:

c

char sql_str[200];
sprintf(sql_str, "UPDATE users SET u_pwd = '%s' WHERE u_name = '%s';", "new_test_pwd", "test_user");
if (mysql_query(conn, sql_str) != 0) {printf("修改数据失败:%s\n", mysql_error(conn));
} else {printf("修改数据成功\n");
}

三、C 语言实现数据库查询操作

查询操作与插入、删除、修改操作有所不同,执行查询指令后,MySQL 会返回一个结果集,我们需要在 C 语言程序中对这个结果集进行处理,提取所需的数据。

1. 结果集相关概念

  • MYSQL_RES:这是 C 语言中用于控制结果集的指针类型,通过它我们可以获取结果集的相关信息,如行数、列数等。
  • MYSQL_ROW:用于表示结果集中的一行数据,通过它我们可以读取一行中各个字段的值。

2. 查询操作执行流程

  • 步骤 1:执行查询 SQL 语句
    使用mysql_query函数执行查询 SQL 语句,例如查询users表中的所有数据:

c

char sql_str[] = "SELECT * FROM users;";
if (mysql_query(conn, sql_str) != 0) {printf("查询数据失败:%s\n", mysql_error(conn));// 失败处理return;
}
  • 步骤 2:获取结果集
    通过mysql_store_result函数获取查询得到的结果集,并赋值给MYSQL_RES类型的指针:

c

MYSQL_RES *result = mysql_store_result(conn);
if (result == NULL) {printf("获取结果集失败:%s\n", mysql_error(conn));// 失败处理return;
}
  • 步骤 3:遍历结果集
    先通过mysql_num_rows函数获取结果集中的行数,通过mysql_num_fields函数获取每行的列数,然后使用mysql_fetch_row函数逐行读取数据,直到读取到 NULL(表示已读取完所有行)。示例代码如下:

c

// 获取行数和列数
int row_count = mysql_num_rows(result);
int col_count = mysql_num_fields(result);
printf("查询到 %d 条数据,每条数据有 %d 个字段\n", row_count, col_count);// 遍历结果集
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)) != NULL) {// 遍历一行中的每个字段for (int i = 0; i < col_count; i++) {printf("%s\t", row[i] ? row[i] : "NULL");}printf("\n");
}
  • 步骤 4:释放结果集
    在完成结果集的遍历后,需要通过mysql_free_result函数释放结果集所占用的内存,避免内存泄漏:

c

mysql_free_result(result);

四、C 语言防 SQL 注入攻击操作

SQL 注入攻击是一种常见的网络攻击手段,攻击者通过在输入框中输入特殊的 SQL 语句片段,改变原有 SQL 语句的逻辑,从而非法获取或修改数据库数据。例如,对于查询用户的 SQL 语句select * from users where u_name='admin' and u_pwd='输入的密码';,若攻击者输入' or '1'='1作为密码,那么 SQL 语句会变成select * from users where u_name='admin' and u_pwd='' or '1'='1';,由于'1'='1'恒为真,攻击者无需正确密码就能查询到数据。

要在 C 语言中规避 SQL 注入攻击,最有效的方法是使用预处理语句(Statement)。预处理语句的核心思想是将 SQL 语句的结构和数据分开处理,先将 SQL 语句的结构发送给 MySQL 服务器进行编译,然后再将数据发送给服务器,这样即使数据中包含特殊字符,也不会被当作 SQL 语句的一部分执行。

预处理语句使用步骤

  • 步骤 1:初始化预处理语句
    使用mysql_stmt_init函数初始化一个预处理语句对象:

c

MYSQL_STMT *stmt = mysql_stmt_init(conn);
if (stmt == NULL) {printf("初始化预处理语句失败:%s\n", mysql_error(conn));// 失败处理return;
}
  • 步骤 2:准备预处理 SQL 语句
    定义带有占位符(?)的 SQL 语句,占位符用于表示后续要传入的数据,然后使用mysql_stmt_prepare函数准备该 SQL 语句:

c

char sql_str[] = "SELECT * FROM users WHERE u_name = ? AND u_pwd = ?;";
if (mysql_stmt_prepare(stmt, sql_str, strlen(sql_str)) != 0) {printf("准备预处理语句失败:%s\n", mysql_stmt_error(stmt));// 失败处理mysql_stmt_close(stmt);return;
}
  • 步骤 3:绑定参数
    定义要传入的参数,并使用mysql_stmt_bind_param函数将参数与预处理语句中的占位符绑定。需要注意的是,要指定参数的类型和长度等信息。例如,绑定用户名和密码参数:

c

char username[50] = "admin";
char password[50] = "admin123";
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));// 绑定用户名参数
bind[0].buffer_type = MYSQL_TYPE_STRING;
bind[0].buffer = username;
bind[0].buffer_length = strlen(username);// 绑定密码参数
bind[1].buffer_type = MYSQL_TYPE_STRING;
bind[1].buffer = password;
bind[1].buffer_length = strlen(password);if (mysql_stmt_bind_param(stmt, bind) != 0) {printf("绑定参数失败:%s\n", mysql_stmt_error(stmt));// 失败处理mysql_stmt_close(stmt);return;
}
  • 步骤 4:执行预处理语句
    使用mysql_stmt_execute函数执行预处理语句:

c

if (mysql_stmt_execute(stmt) != 0) {printf("执行预处理语句失败:%s\n", mysql_stmt_error(stmt));// 失败处理mysql_stmt_close(stmt);return;
}
  • 步骤 5:处理结果集(若为查询操作)
    如果是查询操作,还需要处理返回的结果集,这与前面介绍的普通查询结果集处理类似,但需要使用mysql_stmt_store_resultmysql_stmt_fetch等函数。此处不再详细展开,具体可参考 MySQL 官方文档。
  • 步骤 6:关闭预处理语句
    在完成预处理语句的使用后,需要通过mysql_stmt_close函数关闭预处理语句对象,释放相关资源:

c

mysql_stmt_close(stmt);

通过以上步骤,我们就能有效规避 SQL 注入攻击,保障 C 语言程序与 MySQL 数据库交互的安全性。

总结

本文详细介绍了 C 语言与 MySQL 数据库交互的全流程,从交互流程的搭建,到插入、删除、修改、查询这四类核心数据操作的实现,再到 SQL 注入攻击的防范方法。掌握这些知识,能让你在 C 语言项目开发中灵活地运用 MySQL 数据库进行数据存储和管理。在实际开发中,还需结合具体项目需求,进一步优化代码,确保程序的高效性和安全性。如果你在实践过程中遇到任何问题,欢迎在评论区留言交流!

这篇博客涵盖了 C 与 MySQL 交互的核心内容,若你觉得某些部分需更深入讲解,或想补充特定场景的案例,可随时告知我,我会进一步完善。

http://www.dtcms.com/a/355092.html

相关文章:

  • 多模态大模型研究每日简报【2025-08-28】
  • Logstash数据迁移之es-to-kafka.conf详细配置
  • 5G核心网的架构和功能详解
  • 大模型微调技术
  • 自下而上的树形dp
  • Servlet 注解:简化配置的完整指南
  • 隐语Kuscia正式发布 1.0.0 版本,实现支持 Hive 数据源,支持 envoy 日志进行异常分析等功能
  • hive on tez如果是2个大表union会写几次临时文件到hdfs目录,数据量如何计算
  • hive on tez为什么写表时,要写临时文件到hdfs目录
  • 最长连续序列,leetCode热题100,C++实现
  • 解读 AUTOSAR AP R24-11 Manifest 规范 —— 从部署到安全的全流程支撑
  • 可拖拽指令
  • Xray与XPOC工具对比分析
  • 让企业资产管理高效透明——深度解析固定资产管理系统的功能、优势与价值
  • HBase Compaction HFile 可见性和并发安全性分析
  • Docker-compose离线安装
  • 【Canvas与盾牌】“靡不有初,鲜克有终”黄竖条盾牌
  • [ICCV25]TRACE:用3D高斯直接学习物理参数,让AI“推演”未来场景
  • 微硕WINSOK高性能MOS管WSF80P04,助力充电宝效能与安全升级
  • 在IAR Embedded Workbench for Arm中实现Infineon TRAVEO™ T2G安全调试
  • 舆情监测系统有哪些功能
  • 省市区三级联动选择器-组件
  • C++ 方向 Web 自动化测试实战博客系统思路
  • mac系统本地部署Dify步骤梳理
  • 资产与设备管理数字化转型实践:企业降本增效的新引擎
  • 图书管理系统练习项目源码-前后端分离-【Java版】
  • Linux /proc/pid 探索
  • 【全开源】云贝餐饮V3独立版系统 v1.8.7+API接口开发文档+搭建教程
  • 从 Dockerfile 到 Kubernetes:现代化 PHP 应用配置管理进阶指南
  • 打造旅游实训新场景:旅游管理虚拟仿真实训室的运营与教学落地