SQLite 是全球部署量最大的嵌入式資料庫:零配置、單檔案、ACID 事務、支援大部份 SQL-92、無伺服器進程。本文涵蓋:SQLite 核心特性、命令列工具操作、VC++ 專案整合(靜態庫建置)、C API 核心流程、參數化查詢、事務控制、錯誤處理、效能優化最佳實踐。
.db 檔案即資料庫
# 1. 建立/開啟資料庫
sqlite3.exe mydb.db
# 2. 建表
CREATE TABLE users (
userid VARCHAR(20) PRIMARY KEY,
age INT,
birthday DATETIME
);
# 3. 插入資料
INSERT INTO users VALUES ('wang', 20, '1989-05-04');
INSERT INTO users VALUES ('li', 22, '1987-11-16');
# 4. 查詢
SELECT * FROM users ORDER BY birthday;
# 5. 刪除
DELETE FROM users WHERE userid='wang';
# 6. 結構檢視
.schema users
.tables
# 7. 退出
.exit
元資料儲於 sqlite_master 表,可用 SELECT * FROM sqlite_master 檢視。
sqlite-amalgamation-.zip (單檔源碼)sqlitedll-.zip (預編譯 DLL + .def)
# 開啟 VS 命令提示字元
cd sqlite-amalgamation-3450100
# 直接編譯為 .lib
cl /c /O2 /DTHREADSAFE=1 /DSQLITE_THREADSAFE=1 sqlite3.c
lib /OUT:sqlite3.lib sqlite3.obj
# 或建立靜態庫專案:加入 sqlite3.c + sqlite3.h,配置 Release/Static Runtime
// 標頭檔路徑
// C/C++ → General → Additional Include Directories: $(SolutionDir)sqlite\
// 連結庫
// Linker → General → Additional Library Directories: $(SolutionDir)sqlite\
// Linker → Input → Additional Dependencies: sqlite3.lib
// 代碼中
#include "sqlite3.h"
#pragma comment(lib, "sqlite3.lib")
sqlite3* db = nullptr;
int rc = sqlite3_open("./test.db", &db); // 不存在則建立
if (rc != SQLITE_OK) {
fprintf(stderr, "Open failed: %s\n", sqlite3_errmsg(db));
return 1;
}
// ... 操作 ...
sqlite3_close(db);
static int Callback(void* notUsed, int argc, char** argv, char** colName) {
for (int i = 0; i < argc; i++) {
printf("%s = %s\n", colName[i], argv[i] ? argv[i] : "NULL");
}
printf("----\n");
return 0; // 非零則中止查詢
}
int main() {
sqlite3* db = nullptr;
char* errMsg = nullptr;
int rc;
// 開啟
rc = sqlite3_open("./test.db", &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Open error: %s\n", sqlite3_errmsg(db));
return 1;
}
printf("Database opened!\n");
// 執行多條 SQL(sqlite3_exec 內部自動事務)
const char* sql =
"CREATE TABLE IF NOT EXISTS users("
" userid VARCHAR(20) PRIMARY KEY,"
" age INT,"
" birthday DATETIME"
");"
"INSERT INTO users VALUES('wang', 20, '1989-05-04');"
"INSERT INTO users VALUES('li', 22, '1987-11-16');"
"SELECT * FROM users;";
rc = sqlite3_exec(db, sql, Callback, 0, &errMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
}
sqlite3_close(db);
return 0;
}
預處理語句 是高效能、防 SQL 注入、支援參數綁定的標準做法:
void PreparedStatementDemo(sqlite3* db) {
const char* sql = "INSERT INTO users(userid, age, birthday) VALUES(?, ?, ?);";
sqlite3_stmt* stmt = nullptr;
// 1. 編譯 SQL
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) { /* 錯誤處理 */ return; }
// 2. 綁定參數並執行(可重複)
for (int i = 1; i <= 100; i++) {
char userid[20]; sprintf(userid, "user%d", i);
sqlite3_bind_text(stmt, 1, userid, -1, SQLITE_TRANSIENT); // 參數1
sqlite3_bind_int(stmt, 2, 20 + i % 50); // 參數2
sqlite3_bind_text(stmt, 3, "2000-01-01", -1, SQLITE_STATIC); // 參數3
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) { /* 錯誤 */ }
sqlite3_reset(stmt); // 重置語句供下次使用
}
// 3. 釋放
sqlite3_finalize(stmt);
}
| API | 用途 | 記憶體管理 |
|---|---|---|
sqlite3_bind_text(stmt, idx, val, len, destructor) | 文字 | SQLITE_TRANSIENT複製、SQLITE_STATIC不複製 |
sqlite3_bind_int/stmt, idx, val) | 整數 | 值複製 |
sqlite3_bind_double | 浮點 | 值複製 |
sqlite3_bind_blob | 二進制 | 同 text |
sqlite3_bind_null | NULL值 | -- |
sqlite3_bind_zeroblob | 零填充BLOB | -- |
void TransactionDemo(sqlite3* db) {
sqlite3_exec(db, "BEGIN TRANSACTION;", 0, 0, 0);
// 或 BEGIN IMMEDIATE / BEGIN EXCLUSIVE
bool success = true;
for (int i=0; i<1000; i++) {
if (ExecuteInsert(db, i) != SQLITE_DONE) { success = false; break; }
}
if (success) sqlite3_exec(db, "COMMIT;", 0, 0, 0);
else sqlite3_exec(db, "ROLLBACK;", 0, 0, 0);
}
BEGIN DEFERRED:預設,首次寫入才獲保留鎖BEGIN IMMEDIATE:立即獲保留鎖,減少死鎖BEGIN EXCLUSIVE:獨佔鎖,最高並發安全PRAGMA journal_mode=WAL; 讀寫並行、不阻塞讀取CREATE INDEX idx_age ON users(age);,但避免過度索引PRAGMA page_size=4096;(預設 4KB,大資料量可調 8K/16K/32K/64K)PRAGMA synchronous=NORMAL(平衡安全/速度),FULL 最安全,OFF 最快但掉電風險| 錯誤碼 | 常數 | 含義 | 處理 |
|---|---|---|---|
| 1 | SQLITE_ERROR | 通用錯誤 | 檢查 errMsg |
| 5 | SQLITE_BUSY | 資料庫被鎖 | 設定 busy_timeout、重試、WAL模式 |
| 19 | SQLITE_CONSTRAINT | 約束違反(PK/UNIQUE/NOT NULL) | 檢查資料唯一性 |
| 21 | SQLITE_MISMATCH | 資料型別不匹配 | 綁定參數型別正確 |
| 26 | SQLITE_LOCKED | 表被鎖 | 避免長事務、檢查並發 |
| 場景 | 推薦 | 理由 |
|---|---|---|
| 桌面應用本地存儲 | ✅ SQLite | 零部署、單檔、ACID |
| 移動 App (iOS/Android) | ✅ SQLite | 系統內建、極致輕量 |
| 嵌入式裝置/物聯網 | ✅ SQLite | 無服務、低資源、可靠 |
| 網站低中流量 | ✅ SQLite | 簡單部署、足夠效能 |
| 高併發寫入/大數據量 | ❌ PostgreSQL/MySQL | 需連接池、複雜查詢優化、分布式 |
| 多機器共享資料 | ❌ Client-Server DB | SQLite 無網路協議 |