Linux C如何操作数据库?

99ANYc3cd6
预计阅读时长 38 分钟
位置: 首页 C语言 正文

核心概念

无论使用哪种数据库,C 语言操作数据库的基本流程都是相似的,通常遵循以下步骤:

  1. 包含头文件:包含对应数据库的 C API 头文件。
  2. 初始化环境:创建数据库连接句柄或环境句柄。
  3. 建立连接:使用连接信息(主机、用户、密码、数据库名)连接到数据库服务器。
  4. 执行 SQL 语句
    • 对于查询(SELECT),需要准备语句、绑定结果集、获取数据。
    • 对于更新(INSERT, UPDATE, DELETE),直接执行即可。
  5. 处理结果:遍历查询结果,将数据读取到 C 语言的变量中。
  6. 释放资源:关闭语句、断开连接、释放环境句柄等。
  7. 错误处理:检查每一步操作的返回值,处理可能发生的错误。

操作 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 语言中操作数据库!

-- 展开阅读全文 --
头像
织梦报名插件utf 8
« 上一篇 今天
织梦cms后台模板安装
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]