SQLite接口

下面是一份 SQLite C 接口(C API)完整实战手册,专为 美国开发者(时区 PST/PDT)定制,涵盖:

  • 核心 API 详解
  • 防注入参数化查询
  • 事务、错误处理、回调函数
  • US 本地时间处理(PST/PDT 自动切换)
  • 性能优化(WAL、缓存)
  • 生产级封装模板(C)

一、SQLite C API 核心函数(10 个必会)

函数作用返回值
sqlite3_open()打开数据库SQLITE_OK
sqlite3_prepare_v2()编译 SQLsqlite3_stmt*
sqlite3_step()执行一步SQLITE_ROW / SQLITE_DONE
sqlite3_column_*()读取列值对应类型
sqlite3_bind_*()绑定参数SQLITE_OK
sqlite3_finalize()释放语句SQLITE_OK
sqlite3_close()关闭数据库SQLITE_OK
sqlite3_exec()快速执行 + 回调SQLITE_OK
sqlite3_errmsg()错误信息const char*
sqlite3_changes()影响行数int

二、完整 C 示例:用户管理系统

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

// US 本地时间(自动识别 PST/PDT)
char* now_us() {
    time_t t = time(NULL);
    struct tm *tm = localtime(&t);
    static char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
    return buf;
}

// 回调:打印查询结果
int callback(void *data, int argc, char **argv, char **colName) {
    for (int i = 0; i < argc; i++) {
        printf("%s: %s  ", colName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}

int main() {
    sqlite3 *db;
    sqlite3_stmt *stmt;
    char *errMsg = NULL;
    int rc;

    // 1. 打开数据库
    rc = sqlite3_open("app.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "打开数据库失败: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    // 2. 启用 WAL + 优化
    sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL);
    sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL);
    sqlite3_exec(db, "PRAGMA cache_size = -20000;", NULL, NULL, NULL); // 20MB

    // 3. 创建表
    const char *create_sql = 
        "CREATE TABLE IF NOT EXISTS users ("
        "   id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "   name TEXT NOT NULL,"
        "   email TEXT UNIQUE,"
        "   created_at TEXT DEFAULT (datetime('now', 'localtime'))"
        ");"
        "CREATE INDEX IF NOT EXISTS idx_email ON users(email);";
    sqlite3_exec(db, create_sql, NULL, NULL, &errMsg);

    // 4. 参数化插入(防注入)
    const char *insert_sql = "INSERT INTO users (name, email) VALUES (?, ?);";
    rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "准备语句失败: %s\n", sqlite3_errmsg(db));
        goto cleanup;
    }

    const char *name = "John Doe";
    const char *email = "john@example.com";

    sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, email, -1, SQLITE_TRANSIENT);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        fprintf(stderr, "插入失败: %s\n", sqlite3_errmsg(db));
    } else {
        printf("插入成功,ID: %lld\n", sqlite3_last_insert_rowid(db));
    }

    sqlite3_finalize(stmt);

    // 5. 查询所有用户
    printf("\n--- 用户列表 ---\n");
    sqlite3_exec(db, "SELECT * FROM users;", callback, NULL, &errMsg);

    // 6. 事务批量插入
    sqlite3_exec(db, "BEGIN IMMEDIATE;", NULL, NULL, NULL);
    for (int i = 1; i <= 3; i++) {
        char n[32], e[64];
        snprintf(n, sizeof(n), "User%d", i);
        snprintf(e, sizeof(e), "user%d@test.com", i);

        sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL);
        sqlite3_bind_text(stmt, 1, n, -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(stmt, 2, e, -1, SQLITE_TRANSIENT);
        sqlite3_step(stmt);
        sqlite3_finalize(stmt);
    }
    sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);

    printf("批量插入完成!\n");

cleanup:
    sqlite3_close(db);
    return 0;
}

三、US 时间处理(自动 PST/PDT)

SQLite 不自动识别夏令时,但 localtime 使用系统时区:

// 插入当前 US 时间(自动 PST/PDT)
INSERT INTO logs (action, created_at) 
VALUES ('login', datetime('now', 'localtime'));

C 中获取本地时间

char* now_us() {
    time_t t = time(NULL);
    struct tm *tm = localtime(&t);  // 自动处理 PST/PDT
    static char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);  // 带时区名
    return buf;  // 如: 2025-11-06 17:36:00 PST
}

四、防注入:参数化查询(必须

// 危险:字符串拼接
char sql[256];
snprintf(sql, sizeof(sql), "SELECT * FROM users WHERE email = '%s';", input);

// 安全:参数化
const char *safe_sql = "SELECT * FROM users WHERE email = ?;";
sqlite3_prepare_v2(db, safe_sql, -1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, input, -1, SQLITE_TRANSIENT);

五、生产级封装(推荐)

typedef struct {
    sqlite3 *db;
} DB;

int db_open(DB *db, const char *path) {
    return sqlite3_open(path, &db->db);
}

void db_close(DB *db) {
    if (db->db) sqlite3_close(db->db);
}

int db_exec(DB *db, const char *sql) {
    char *err;
    int rc = sqlite3_exec(db->db, sql, NULL, NULL, &err);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", err);
        sqlite3_free(err);
    }
    return rc;
}

六、性能优化(US 高并发场景)

// 开启 WAL(推荐生产)
sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL);

// 增大缓存
sqlite3_exec(db, "PRAGMA cache_size = -64000;", NULL, NULL, NULL); // 64MB

// 页面大小
sqlite3_exec(db, "PRAGMA page_size = 4096;", NULL, NULL, NULL);

七、编译命令

# Linux/macOS
gcc main.c -lsqlite3 -o app

# Windows (MinGW)
gcc main.c -lsqlite3 -o app.exe

# 静态链接(嵌入式)
gcc sqlite3.c your_app.c -pthread -ldl -lm -o app

八、常见错误处理

错误检查点
SQLITE_BUSY数据库被锁 → 用 WAL 或重试
SQLITE_CONSTRAINT唯一约束冲突
SQLITE_ERRORSQL 语法错误
内存泄漏每个 prepare 必须 finalize
if (rc != SQLITE_OK) {
    fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
    goto cleanup;
}

九、快速模板(复制即用)

1. 安全查询单条

const char *get_email(sqlite3 *db, int id) {
    const char *sql = "SELECT email FROM users WHERE id = ?;";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
    sqlite3_bind_int(stmt, 1, id);
    if (sqlite3_step(stmt) == SQLITE_ROW) {
        const char *email = (const char*)sqlite3_column_text(stmt, 0);
        char *result = strdup(email);
        sqlite3_finalize(stmt);
        return result;
    }
    sqlite3_finalize(stmt);
    return NULL;
}

2. 带回调查询

sqlite3_exec(db, "SELECT * FROM users WHERE created_at > '2025-11-01';", callback, NULL, NULL);

十、总结:C API 最佳实践

项目推荐
防注入必须用 ? + sqlite3_bind_*
时间datetime('now','localtime')
事务批量操作用 BEGIN ... COMMIT
并发开启 WAL
资源finalize + close
错误每次检查 rc

需要我为你生成:

  • REST API 后端(C + SQLite)
  • 高性能日志系统(100K QPS)
  • iOS/Android NDK 封装

把需求发我,10 分钟出完整代码

文章已创建 2326

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部