SQLite – C/C++(二)
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_ERROR | SQL 语法错误 |
SQLITE_BUSY | 数据库被锁住 |
SQLITE_LOCKED | 事务锁定错误 |
SQLITE_NOMEM | 内存不足 |
SQLITE_IOERR | I/O 读写错误 |
总结
- 使用 事务 (
BEGIN, COMMIT, ROLLBACK) 提高性能 - 使用 预编译查询 (
sqlite3_prepare_v2()) 进行高效查询 - 使用
sqlite3_bind_*()绑定参数,防止 SQL 注入 - 处理 BLOB 数据 (
sqlite3_bind_blob()) - 多线程模式需要 配置
sqlite3_config() - 使用
sqlite3_errmsg()进行错误处理
更多详细内容请关注其他相关文章。