SQLite – C/C++(二)
                           
天天向上
发布: 2025-03-05 22:57:28

原创
965 人浏览过

SQLite 在 C/C++ 中提供了丰富的 API,可以实现数据库的创建、查询、事务管理、多线程支持等功能。以下是更详细的介绍,包括事务处理、预编译查询、BLOB 数据存储、错误处理、多线程使用等进阶内容。


1. SQLite C API 详细介绍

SQLite 提供了以下 API 进行数据库操作:

API作用
sqlite3_open()打开数据库
sqlite3_close()关闭数据库
sqlite3_exec()执行 SQL 语句
sqlite3_prepare_v2()预编译 SQL 语句
sqlite3_step()执行预编译 SQL 语句
sqlite3_finalize()释放 SQL 语句对象
sqlite3_errmsg()获取错误消息
sqlite3_bind_*()绑定参数到 SQL 语句
sqlite3_column_*()获取查询结果
sqlite3_begin_transaction()开启事务
sqlite3_commit()提交事务
sqlite3_rollback()回滚事务

2. 使用事务 (BEGIN, COMMIT, ROLLBACK)

SQLite 默认是 自动提交模式,但你可以使用 事务 提高性能。

示例:使用事务插入数据

#include <stdio.h>
#include <sqlite3.h>

int main() {
    sqlite3 *db;
    char *errMsg = 0;
    int rc;

    // 打开数据库
    rc = sqlite3_open("test.db", &db);
    if (rc) {
        printf("无法打开数据库: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    // 开启事务
    sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errMsg);

    // 插入多条数据
    const char *sql = "INSERT INTO users (name) VALUES ('Charlie');"
                      "INSERT INTO users (name) VALUES ('David');";
    rc = sqlite3_exec(db, sql, 0, 0, &errMsg);

    if (rc != SQLITE_OK) {
        printf("插入数据失败: %s\n", errMsg);
        sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);  // 事务回滚
        sqlite3_free(errMsg);
    } else {
        sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);  // 事务提交
        printf("数据插入成功!\n");
    }

    sqlite3_close(db);
    return 0;
}

事务的好处

  • 保证数据完整性:如果中间某个 SQL 语句失败,整个事务都不会生效(回滚)。
  • 提升性能:在事务内批量执行 SQL 语句,比逐条执行快很多。

3. 预编译 SQL 查询(sqlite3_prepare_v2)

使用 sqlite3_exec() 执行 SQL 并不适合查询大量数据,因为它一次性解析 SQL 语句并执行。可以使用 sqlite3_prepare_v2() 进行预编译查询,然后用 sqlite3_step() 获取结果。

示例:使用 sqlite3_prepare_v2() 查询数据

#include <stdio.h>
#include <sqlite3.h>

int main() {
    sqlite3 *db;
    sqlite3_stmt *stmt;
    int rc;

    // 打开数据库
    rc = sqlite3_open("test.db", &db);
    if (rc) {
        printf("无法打开数据库: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    // 预编译 SQL 语句
    const char *sql = "SELECT id, name FROM users WHERE name = ?;";
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);

    if (rc != SQLITE_OK) {
        printf("SQL 预编译失败: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    // 绑定参数 (防止 SQL 注入)
    sqlite3_bind_text(stmt, 1, "Alice", -1, SQLITE_STATIC);

    // 逐行获取结果
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        int id = sqlite3_column_int(stmt, 0);
        const unsigned char *name = sqlite3_column_text(stmt, 1);
        printf("ID: %d, Name: %s\n", id, name);
    }

    // 释放资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

sqlite3_bind_text() 作用

  • 防止 SQL 注入
  • 提高性能(SQL 语句只解析一次)

4. 处理 BLOB 数据

SQLite 支持存储 二进制数据(BLOB),例如图片、音频等。

示例:存储 BLOB

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>

int main() {
    sqlite3 *db;
    sqlite3_stmt *stmt;
    FILE *file;
    long file_size;
    unsigned char *buffer;

    // 打开数据库
    sqlite3_open("test.db", &db);

    // 读取文件到内存
    file = fopen("image.jpg", "rb");
    fseek(file, 0, SEEK_END);
    file_size = ftell(file);
    rewind(file);
    buffer = (unsigned char *)malloc(file_size);
    fread(buffer, file_size, 1, file);
    fclose(file);

    // 预编译 SQL 语句
    const char *sql = "INSERT INTO images (data) VALUES (?);";
    sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    sqlite3_bind_blob(stmt, 1, buffer, file_size, SQLITE_STATIC);

    // 执行语句
    sqlite3_step(stmt);

    // 释放资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    free(buffer);

    printf("BLOB 数据插入成功!\n");
    return 0;
}

使用 sqlite3_bind_blob() 处理二进制数据

  • 适用于 图片、音频、视频、加密文件等二进制数据
  • sqlite3_column_blob() 可以用于读取 BLOB 数据

5. 多线程支持

默认情况下,SQLite 不支持多个线程同时写入。如果你需要多线程支持,需要:

  • 打开多线程模式
  • 使用 sqlite3_busy_timeout() 避免死锁
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
sqlite3_busy_timeout(db, 5000);  // 设置超时时间 5 秒

6. 错误处理

SQLite 提供了 错误码 以便进行错误处理:

int rc = sqlite3_exec(db, sql, 0, 0, &errMsg);
if (rc != SQLITE_OK) {
    printf("错误: %s\n", sqlite3_errmsg(db));
    sqlite3_free(errMsg);
}

常见错误码

错误码含义
SQLITE_OK成功
SQLITE_ERRORSQL 语法错误
SQLITE_BUSY数据库被锁住
SQLITE_LOCKED事务锁定错误
SQLITE_NOMEM内存不足
SQLITE_IOERRI/O 读写错误

总结

  • 使用 事务 (BEGIN, COMMIT, ROLLBACK) 提高性能
  • 使用 预编译查询 (sqlite3_prepare_v2()) 进行高效查询
  • 使用 sqlite3_bind_*() 绑定参数,防止 SQL 注入
  • 处理 BLOB 数据 (sqlite3_bind_blob())
  • 多线程模式需要 配置 sqlite3_config()
  • 使用 sqlite3_errmsg() 进行错误处理

更多详细内容请关注其他相关文章。

发表回复 0

Your email address will not be published. Required fields are marked *