sqlite c语言api

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

这篇指南将从基础到高级,涵盖最常用和最重要的 API 函数。

sqlite c语言api
(图片来源网络,侵删)

核心概念与流程

使用 SQLite C API 的基本流程非常固定,遵循以下步骤:

  1. 打开数据库:使用 sqlite3_open() 函数,如果数据库文件不存在,它会自动创建。
  2. 准备 SQL 语句:使用 sqlite3_prepare_v2() 将 SQL 字符串编译成一个内部语句对象,这一步可以防止 SQL 注入。
  3. 绑定参数(可选):SQL 语句包含参数( 或 name),使用 sqlite3_bind_*() 系列函数将 C 变量绑定到这些参数。
  4. 执行语句:使用 sqlite3_step() 逐行执行 SQL 语句,对于 SELECT 语句,每调用一次 step 就会返回一行结果。
  5. 获取结果:在 sqlite3_step() 返回 SQLITE_ROW 后,使用 sqlite3_column_*() 系列函数获取当前行的列数据。
  6. 重置语句(可选):如果需要重复执行同一语句(例如在循环中),可以调用 sqlite3_reset() 将语句对象重置到初始状态,然后再次绑定新参数并调用 step
  7. 清理语句:使用 sqlite3_finalize() 释放准备语句对象占用的资源。
  8. 关闭数据库:使用 sqlite3_close() 关闭数据库连接。

核心数据结构

  • sqlite3:这是一个不透明的结构体,代表一个数据库连接,你不需要关心其内部结构,只需将它作为句柄传递给所有 API 函数。
  • sqlite3_stmt:这也是一个不透明的结构体,代表一个已编译的 SQL 语句。

关键 API 函数详解

1. 打开和关闭数据库

// 打开或创建一个数据库
int sqlite3_open(
  const char *filename,   // 数据库文件名。":memory:" 表示在内存中创建数据库
  sqlite3 **ppDb         // 输出参数,用于存储数据库连接句柄
);
// 关闭数据库连接
int sqlite3_close(sqlite3 *db);

返回值

  • SQLITE_OK: 成功。
  • 其他值: 失败,可以通过 sqlite3_errmsg(db) 获取错误信息。

示例

sqlite3 *db;
int rc = sqlite3_open("test.db", &db);
if (rc != SQLITE_OK) {
    fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
    return 1;
}
// ... 使用数据库 ...
sqlite3_close(db);

2. 准备和清理语句

// 将 SQL 语句编译成一个语句对象
int sqlite3_prepare_v2(
  sqlite3 *db,            // 数据库连接
  const char *zSql,       // SQL 语句字符串
  int nByte,              // SQL 语句的字节长度 (-1 表示以 NULL 
  sqlite3 **ppStmt,       // 输出参数,用于存储语句句柄
  const char **pzTail     // 输出参数,指向第一个未使用的字节 (通常设为 NULL)
);
// 销毁一个语句对象,释放其占用的资源
int sqlite3_finalize(sqlite3 *stmt);

返回值

sqlite c语言api
(图片来源网络,侵删)
  • SQLITE_OK: 成功。
  • SQLITE_ERROR: SQL 语法错误。
  • SQLITE_BUSY: 数据库被锁定。

示例

sqlite3_stmt *stmt;
const char *sql = "SELECT id, name FROM users WHERE age > ?";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
    fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
    return 1;
}
// ... 使用语句 ...
sqlite3_finalize(stmt);

3. 绑定参数(防止 SQL 注入)

对于带有 或 name 占位符的 SQL 语句,绑定参数是最佳实践。

// 绑定一个整数
int sqlite3_bind_int(sqlite3_stmt*, int, int);
// 绑定一个 64 位整数
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
// 绑定一个浮点数
int sqlite3_bind_double(sqlite3_stmt*, int, double);
// 绑定一个文本 (UTF-8)
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
// 绑定一个 NULL 值
int sqlite3_bind_null(sqlite3_stmt*, int);

参数说明

  • sqlite3_stmt*: 语句句柄。
  • int: 参数的索引,从 1 开始。
  • const char*: 要绑定的文本字符串。
  • int n: 文本的字节数,如果为 -1,则函数会自动计算以 NULL 结尾的字符串长度。
  • void(*)(void*): 一个析构函数,用于在语句执行完毕后释放文本内存,通常传入 SQLITE_STATIC (表示字符串是常量,无需释放) 或 SQLITE_TRANSIENT (告诉 SQLite 复制一份字符串,由 SQLite 负责释放)。

示例

int age = 30;
rc = sqlite3_bind_int(stmt, 1, age); // 绑定到第一个参数 '?'
if (rc != SQLITE_OK) {
    // 错误处理
}

4. 执行语句

// 执行一条准备好的语句
int sqlite3_step(sqlite3_stmt *stmt);

返回值

  • SQLITE_ROW: 语句执行成功,并且返回了一行数据(仅用于 SELECT 及相关查询)。
  • SQLITE_DONE: 语句执行成功,并且没有更多行可返回(用于 INSERT, UPDATE, DELETE 等)。
  • SQLITE_ERROR: 发生错误。
  • SQLITE_BUSY: 数据库被锁定。

示例

// 对于 INSERT/UPDATE/DELETE
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
    fprintf(stderr, "Execution failed: %s\n", sqlite3_errmsg(db));
}
// 对于 SELECT
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
    // 处理当前行...
}
if (rc != SQLITE_DONE) {
    fprintf(stderr, "Query failed: %s\n", sqlite3_errmsg(db));
}

5. 获取查询结果

sqlite3_step() 返回 SQLITE_ROW 时,可以使用以下函数获取列数据。

// 获取列的数据类型
int sqlite3_column_type(sqlite3_stmt*, int iCol);
// 获取列的值
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
const unsigned char* sqlite3_column_text(sqlite3_stmt*, int iCol); // 返回 UTF-8 字符串
const void* sqlite3_column_blob(sqlite3_stmt*, int iCol);          // 返回二进制数据
// 获取列的字节长度
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
// 获取列的名称
const char* sqlite3_column_name(sqlite3_stmt*, int iCol);

参数说明

  • sqlite3_stmt*: 语句句柄。
  • int iCol: 列的索引,从 0 开始。

示例

int id_col = sqlite3_column_index(stmt, "id");
int name_col = sqlite3_column_index(stmt, "name");
// 或者通过索引获取
int id_col = 0;
int name_col = 1;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
    int id = sqlite3_column_int(stmt, id_col);
    const unsigned char *name = sqlite3_column_text(stmt, name_col);
    printf("ID: %d, Name: %s\n", id, name);
}

完整示例代码

下面是一个完整的 C 程序,演示了创建表、插入数据(带参数绑定)、查询数据并打印结果的完整流程。

#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
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(int argc, char* argv[]) {
    sqlite3 *db;
    char *zErrMsg = 0;
    int rc;
    // 1. 打开数据库
    rc = sqlite3_open("test.db", &db);
    if (rc) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return(1);
    } else {
        fprintf(stdout, "Opened database successfully\n");
    }
    // 2. 创建表 (使用 exec 接口简化)
    const char* sql_create_table = "CREATE TABLE IF NOT EXISTS COMPANY("
                                  "ID INT PRIMARY KEY     NOT NULL,"
                                  "NAME           TEXT    NOT NULL,"
                                  "AGE            INT     NOT NULL,"
                                  "ADDRESS        CHAR(50),"
                                  "SALARY         REAL );";
    rc = sqlite3_exec(db, sql_create_table, callback, 0, &zErrMsg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    } else {
        fprintf(stdout, "Table created successfully\n");
    }
    // 3. 插入数据 (使用 prepare/step/bind 接口)
    const char* sql_insert = "INSERT INTO COMPANY (ID, NAME, AGE, ADDRESS, SALARY) "
                             "VALUES (?, ?, ?, ?, ?);";
    sqlite3_stmt *stmt;
    rc = sqlite3_prepare_v2(db, sql_insert, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Failed to prepare insert statement: %s\n", sqlite3_errmsg(db));
        return 1;
    }
    // 绑定参数并插入第一行
    sqlite3_bind_int(stmt, 1, 1);
    sqlite3_bind_text(stmt, 2, "Paul", -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 3, 32);
    sqlite3_bind_text(stmt, 4, "California", -1, SQLITE_STATIC);
    sqlite3_bind_double(stmt, 5, 20000.0);
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Execution failed: %s\n", sqlite3_errmsg(db));
    }
    sqlite3_reset(stmt); // 重置语句以复用
    // 绑定参数并插入第二行
    sqlite3_bind_int(stmt, 1, 2);
    sqlite3_bind_text(stmt, 2, "Allen", -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 3, 25);
    sqlite3_bind_text(stmt, 4, "Texas", -1, SQLITE_STATIC);
    sqlite3_bind_double(stmt, 5, 15000.0);
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Execution failed: %s\n", sqlite3_errmsg(db));
    }
    sqlite3_finalize(stmt); // 清理语句
    fprintf(stdout, "Records created successfully\n");
    // 4. 查询数据
    const char* sql_select = "SELECT * FROM COMPANY;";
    rc = sqlite3_exec(db, sql_select, callback, 0, &zErrMsg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    } else {
        fprintf(stdout, "Operation done successfully\n");
    }
    // 5. 关闭数据库
    sqlite3_close(db);
    return 0;
}

编译与运行

将上述代码保存为 main.c,然后使用 GCC 进行编译:

gcc main.c -o sqlite_test -lsqlite3

运行生成的可执行文件:

./sqlite_test

程序执行后,会在当前目录下创建一个 test.db 文件,并执行所有数据库操作。

高级主题

  • 事务:使用 BEGIN TRANSACTION, COMMIT, ROLLBACK SQL 语句来控制事务,API 中没有直接的函数,但可以通过 sqlite3_exec() 执行这些命令。
  • 错误处理:始终检查每个 API 函数的返回值,并使用 sqlite3_errmsg()sqlite3_errstr() 来获取有意义的错误信息。
  • 回调函数sqlite3_exec() 提供了一个便捷的回调机制来处理 SELECT 查询的结果,它会在每一行数据返回时调用你提供的函数,对于复杂的应用,直接使用 sqlite3_prepare_v2 + sqlite3_step + sqlite3_column_* 的方式更灵活。
  • 线程安全:SQLite 支持三种线程模式:单线程、串行化和多线程,在编译时需要指定相应的选项,默认情况下(-DSQLITE_THREADSAFE=1)是串行化模式,是线程安全的。

希望这份详细的指南能帮助你掌握 SQLite 的 C 语言 API!

-- 展开阅读全文 --
头像
unsigned输出为何结果异常?
« 上一篇 今天
dede tagindex如何正确配置与使用?
下一篇 » 今天

相关文章

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

目录[+]