sqlite3_open打开失败常见原因包括:路径含中文或空格未转义、当前工作目录与预期不符、文件被其他进程锁定(如db browser未关闭)、权限不足;建议优先使用绝对路径并验证cwd。

用 sqlite3_open 打开数据库文件失败,常见原因是什么?
sqlite3_open 返回非零值(比如 SQLITE_CANTOPEN)时,并不总是因为文件不存在。更常踩的坑是:路径含中文或空格但没做转义、当前工作目录和预期不符、文件被其他进程独占锁定(尤其是 Windows 下用 DB Browser 打开后忘了关)、或者权限不足(Linux/macOS 上文件不可读)。建议先用绝对路径测试,例如 /home/user/data.db 或 C:\temp\test.db;若用相对路径,确认程序运行时的 cwd 确实是你认为的那个目录——可以用 getcwd 或 _getcwd 打印出来验证。
执行 SQL 查询后如何安全获取字符串字段?
SQLite 的 C 接口返回的是裸指针(const char*),指向内部缓冲区,不能直接 strcpy 或存为 std::string 后就不管了。必须在同一次 sqlite3_step 调用上下文中使用,否则下次 step 或 finalize 后内存可能失效。正确做法是立即拷贝:
const char* txt = sqlite3_column_text(stmt, 0);
if (txt) {
std::string s(txt); // 拷贝构造
}
注意:sqlite3_column_text 对 NULL 字段返回 nullptr,不判空直接解引用会崩溃;而 sqlite3_column_bytes 在字段为 NULL 时返回 0,不是字符串长度——它返回的是 UTF-8 字节数,不是 strlen。
为什么用 sqlite3_prepare_v2 而不是 sqlite3_exec?
sqlite3_exec 看似简单,但它把 SQL 当作纯文本拼接执行,无法防止 SQL 注入,也不支持参数绑定。只要涉及用户输入(哪怕只是 ID 查询),就必须用 sqlite3_prepare_v2 + sqlite3<em>bind</em>*。例如:
sqlite3_stmt* stmt; sqlite3_prepare_v2(db, "SELECT name FROM users WHERE id = ?", -1, &stmt, nullptr); sqlite3_bind_int(stmt, 1, user_id); // 绑定整数 sqlite3_step(stmt);
用 ? 占位符比 sqlite3_mprintf 拼接字符串安全得多,也避免类型转换错误(比如把浮点当整数传)。
忘记调用 sqlite3_finalize 会怎样?
不会立刻崩溃,但会导致内存泄漏和句柄泄露。每个 sqlite3_prepare_v2 都分配资源,SQLite 内部有语句缓存上限(默认 100),超限后新 prepare 可能变慢甚至失败。更隐蔽的问题是:如果在循环里反复 prepare 同一条 SQL 却不 finalize,等于不断创建新语句对象,最终耗尽资源。务必配对使用:
- 每个
sqlite3_prepare_v2对应一个sqlite3_finalize - 即使
prepare失败,stmt可能仍为非空,也要检查并finalize -
sqlite3_close不会自动释放未finalize的语句
C++ 封装时建议用 RAII(如 std::unique_ptr 配自定义 deleter),但原生 C 接口里,这一步最容易被跳过。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











