核心概念
无论使用哪种数据库,C 语言操作数据库的基本流程都是相似的,通常遵循以下步骤:
- 包含头文件:包含对应数据库的 C API 头文件。
- 初始化环境:创建数据库连接句柄或环境句柄。
- 建立连接:使用连接信息(主机、用户、密码、数据库名)连接到数据库服务器。
- 执行 SQL 语句:
- 对于查询(
SELECT),需要准备语句、绑定结果集、获取数据。 - 对于更新(
INSERT,UPDATE,DELETE),直接执行即可。
- 对于查询(
- 处理结果:遍历查询结果,将数据读取到 C 语言的变量中。
- 释放资源:关闭语句、断开连接、释放环境句柄等。
- 错误处理:检查每一步操作的返回值,处理可能发生的错误。
操作 MySQL / MariaDB (最常用)
MySQL 和 MariaDB 的 C API 非常成熟,广泛应用于各种 Web 应用和后端服务中。
安装开发库
你需要安装 MySQL 或 MariaDB 的 C 开发库,在基于 Debian/Ubuntu 的系统上:
# 对于 MySQL sudo apt-get install libmysqlclient-dev # 对于 MariaDB sudo apt-get install libmariadb-client-lgpl-dev
在基于 RedHat/CentOS 的系统上:
# 对于 MySQL sudo yum install mysql-devel # 对于 MariaDB sudo yum install mariadb-devel
示例代码
下面是一个完整的 C 程序示例,它连接到本地 MySQL 服务器,创建一个表,插入数据,然后查询并打印结果。
// mysql_example.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h> // 使用 mysql.h 或 mariadb/mysql.h
// 定义数据库连接信息
#define DB_HOST "localhost"
#define DB_USER "root"
#define DB_PASS "your_password" // 请替换为你的密码
#define DB_NAME "test_db"
void finish_with_error(MYSQL *mysql) {
fprintf(stderr, "Error (%d): %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
exit(1);
}
int main() {
MYSQL *mysql = mysql_init(NULL);
if (mysql == NULL) {
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
// 建立连接
if (mysql_real_connect(mysql, DB_HOST, DB_USER, DB_PASS, DB_NAME, 0, NULL, 0) == NULL) {
finish_with_error(mysql);
}
printf("Successfully connected to the database.\n");
// --- 1. 创建表 ---
if (mysql_query(mysql, "DROP TABLE IF EXISTS users")) {
finish_with_error(mysql);
}
if (mysql_query(mysql, "CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), email VARCHAR(50))")) {
finish_with_error(mysql);
}
printf("Table 'users' created or already exists.\n");
// --- 2. 插入数据 ---
const char *insert_query = "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com'), ('Bob', 'bob@example.com')";
if (mysql_query(mysql, insert_query)) {
finish_with_error(mysql);
}
printf("Data inserted successfully.\n");
// --- 3. 查询数据 ---
if (mysql_query(mysql, "SELECT id, name, email FROM users")) {
finish_with_error(mysql);
}
// 获取结果集
MYSQL_RES *result = mysql_store_result(mysql);
if (result == NULL) {
if (mysql_field_count(mysql) == 0) {
// 这是一个没有结果集的查询 (如 INSERT, UPDATE)
printf("No data or rows affected.\n");
} else {
finish_with_error(mysql);
}
}
// 获取列数
int num_fields = mysql_num_fields(result);
// 获取字段名(列名)
MYSQL_FIELD *field;
printf("\n--- Query Results ---\n");
while ((field = mysql_fetch_field(result))) {
printf("%-15s", field->name);
}
printf("\n");
// 遍历每一行
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
for(int i = 0; i < num_fields; i++) {
printf("%-15s", row[i] ? row[i] : "NULL");
}
printf("\n");
}
// 释放结果集
mysql_free_result(result);
// 关闭连接
mysql_close(mysql);
printf("\nDatabase connection closed.\n");
return 0;
}
编译与运行
使用 gcc 进行编译,需要链接 mysqlclient 库。
gcc mysql_example.c -o mysql_example -lmysqlclient # 运行 (如果需要,可能需要指定库路径) # ./mysql_example
操作 SQLite (最轻量级)
SQLite 是一个嵌入式数据库,它是一个 C 语言库,无需独立的服务器进程,非常适合桌面应用、移动应用和小型项目。
安装开发库
SQLite 的库和头文件通常打包在一起。
# Debian/Ubuntu sudo apt-get install libsqlite3-dev # RedHat/CentOS sudo yum install sqlite-devel
示例代码
这个示例展示了如何使用 SQLite 的 C API,其流程与 MySQL 类似,但 API 更简洁。
// sqlite_example.c
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#define DB_FILE "test.db"
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
for (i = 0; i < argc; i++) {
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main() {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
// 1. 打开数据库文件,如果不存在则创建
rc = sqlite3_open(DB_FILE, &db);
if (rc) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return(1);
}
printf("Successfully opened database.\n");
// 2. 创建表
const char *sql = "CREATE TABLE IF NOT EXISTS users ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT NOT NULL,"
"email TEXT NOT NULL);";
rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
sqlite3_close(db);
return 1;
}
printf("Table 'users' created or already exists.\n");
// 3. 插入数据
sql = "INSERT INTO users (name, email) VALUES ('Charlie', 'charlie@example.com');"
"INSERT INTO users (name, email) VALUES ('David', 'david@example.com');";
rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
printf("Data inserted successfully.\n");
}
// 4. 查询数据
sql = "SELECT id, name, email FROM users;";
printf("\n--- Query Results ---\n");
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
// 5. 关闭数据库
sqlite3_close(db);
printf("\nDatabase connection closed.\n");
return 0;
}
编译与运行
编译时链接 sqlite3 库。
gcc sqlite_example.c -o sqlite_example -lsqlite3 # 运行 ./sqlite_example
运行后,你会发现当前目录下多了一个 test.db 文件,这就是 SQLite 的数据库文件。
操作 PostgreSQL (功能强大)
PostgreSQL 是一个功能非常强大的开源对象关系型数据库,以其标准兼容性和丰富的功能著称。
安装开发库
# Debian/Ubuntu sudo apt-get install libpq-dev # RedHat/CentOS sudo yum install postgresql-devel
示例代码
PostgreSQL 的 C API (libpq) 使用起来也比较直接。
// postgres_example.c
#include <stdio.h>
#include <stdlib.h>
#include <libpq-fe.h>
#define DB_HOST "localhost"
#define DB_NAME "test_db"
#define DB_USER "postgres"
#define DB_PASS "your_password" // 请替换为你的密码
void finish_with_error(PGconn *conn) {
fprintf(stderr, "Database connection error: %s\n", PQerrorMessage(conn));
PQfinish(conn);
exit(1);
}
int main() {
// 1. 建立连接
// 连接字符串格式:host=dbname=user=password=
char conninfo[256];
snprintf(conninfo, sizeof(conninfo), "host=%s dbname=%s user=%s password=%s",
DB_HOST, DB_NAME, DB_USER, DB_PASS);
PGconn *conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK) {
finish_with_error(conn);
}
printf("Successfully connected to the database.\n");
// 2. 创建表
const char *create_table_query = "DROP TABLE IF EXISTS products; CREATE TABLE products (id SERIAL PRIMARY KEY, name VARCHAR(100), price NUMERIC(10, 2));";
PGresult *res = PQexec(conn, create_table_query);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "Create table failed: %s", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
PQclear(res);
printf("Table 'products' created or already exists.\n");
// 3. 插入数据 (使用参数化查询防止SQL注入)
const char *insert_query = "INSERT INTO products (name, price) VALUES ($1, $2)";
res = PQprepare(conn, "insert_product", insert_query, 2, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "Prepare failed: %s", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
PQclear(res);
const char *paramValues[2] = {"Laptop", "1200.50"};
res = PQexecPrepared(conn, "insert_product", 2, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "Insert failed: %s", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
PQclear(res);
printf("Data inserted successfully.\n");
// 4. 查询数据
const char *select_query = "SELECT id, name, price FROM products";
res = PQexec(conn, select_query);
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
fprintf(stderr, "Select failed: %s", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
printf("\n--- Query Results ---\n");
int nFields = PQnfields(res);
for (int i = 0; i < nFields; i++) {
printf("%-15s", PQfname(res, i));
}
printf("\n");
for (int i = 0; i < PQntuples(res); i++) {
for (int j = 0; j < nFields; j++) {
printf("%-15s", PQgetvalue(res, i, j));
}
printf("\n");
}
PQclear(res);
// 5. 关闭连接
PQfinish(conn);
printf("\nDatabase connection closed.\n");
return 0;
}
编译与运行
编译时链接 pq 库。
gcc postgres_example.c -o postgres_example -lpq # 运行 ./postgres_example
如何选择?
| 特性 | MySQL / MariaDB | SQLite | PostgreSQL |
|---|---|---|---|
| 类型 | 客户端/服务器 | 嵌入式 | 客户端/服务器 |
| 适用场景 | Web应用、后端服务、需要高并发 | 桌面/移动应用、小型项目、IoT | 复杂数据分析、地理信息、需要强一致性和事务 |
| 优点 | 速度快、文档丰富、社区庞大 | 零配置、轻量级、单个文件 | 功能强大、标准兼容性好、扩展性强 |
| 缺点 | 功能相对较少(社区版) | 并发能力有限,不适合高负载 | 配置复杂,资源消耗较大 |
| C API | libmysqlclient |
sqlite3 |
libpq |
总结建议:
- 如果你是初学者,或者在做Web后端,MySQL/MariaDB 是最稳妥、最常见的选择。
- 如果你在开发一个桌面应用、手机 App 或者一个小工具,并且不想安装和管理一个数据库服务器,SQLite 是不二之选。
- 如果你的项目对数据一致性、事务、复杂查询有很高的要求,或者需要使用高级数据类型(如JSON、GIS),PostgreSQL 是最佳选择。
希望这份详细的指南能帮助你开始在 Linux C 语言中操作数据库!
