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

(图片来源网络,侵删)
核心概念与流程
使用 SQLite C API 的基本流程非常固定,遵循以下步骤:
- 打开数据库:使用
sqlite3_open()函数,如果数据库文件不存在,它会自动创建。 - 准备 SQL 语句:使用
sqlite3_prepare_v2()将 SQL 字符串编译成一个内部语句对象,这一步可以防止 SQL 注入。 - 绑定参数(可选):SQL 语句包含参数( 或
name),使用sqlite3_bind_*()系列函数将 C 变量绑定到这些参数。 - 执行语句:使用
sqlite3_step()逐行执行 SQL 语句,对于SELECT语句,每调用一次step就会返回一行结果。 - 获取结果:在
sqlite3_step()返回SQLITE_ROW后,使用sqlite3_column_*()系列函数获取当前行的列数据。 - 重置语句(可选):如果需要重复执行同一语句(例如在循环中),可以调用
sqlite3_reset()将语句对象重置到初始状态,然后再次绑定新参数并调用step。 - 清理语句:使用
sqlite3_finalize()释放准备语句对象占用的资源。 - 关闭数据库:使用
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_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,ROLLBACKSQL 语句来控制事务,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!
