如何在多个连接之间共享SQLite内存数据库
问题根因
你当前的错误是由连接配置和路径格式错误导致的,所有打开的连接实际创建了独立的私有内存数据库,自然无法互相访问数据。
必须修改的核心点
- 必须使用完整的URI格式的数据库路径:
file:zmem?mode=memory&cache=shared,不能仅使用zmem作为连接名 - 打开连接时需要添加
SQLITE_OPEN_URIflag启用URI解析功能,或者全局调用sqlite3_config(SQLITE_CONFIG_URI, 1)开启全局URI支持 - 删除打开flag中的
SQLITE_OPEN_MEMORY,该参数会强制每个连接创建独立的私有匿名内存库,和共享内存数据库的需求冲突 - 多线程场景下如果没有自行实现并发访问控制,建议将
SQLITE_OPEN_NOMUTEX替换为SQLITE_OPEN_FULLMUTEX,避免线程安全问题
修改后可运行的完整代码
#include <sqlite3.h> #include <stdio.h> int exec(sqlite3 *db, char* sql) { sqlite3_stmt *stmt; int ret; do { ret = sqlite3_prepare_v2(db, sql, -1, &stmt, 0); if (ret != SQLITE_OK) { printf("prep error: %s", sqlite3_errmsg(db)); break; } ret = sqlite3_step(stmt); if (ret != SQLITE_DONE) { printf("step error: %s", sqlite3_errmsg(db)); break; } ret = SQLITE_OK; } while(0); sqlite3_finalize(stmt); return ret; } sqlite3* getCon(char *name) { sqlite3 *db = 0; // 修改flags:去掉SQLITE_OPEN_MEMORY,添加SQLITE_OPEN_URI int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_URI; int ret = sqlite3_open_v2(name, &db, flags, 0); if (ret != SQLITE_OK) { printf("open error: %s", sqlite3_errmsg(db)); } return db; } void query(sqlite3 *db) { sqlite3_stmt *stmt = 0; do { int ret = sqlite3_prepare_v2(db, "SELECT * FROM MyTable", -1, &stmt, 0); if (ret != SQLITE_OK) { printf("prep error: %s\n", sqlite3_errmsg(db)); break; } while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) { char *name = (char *) sqlite3_column_text(stmt, 0); printf("%s\n", name); } if (ret != SQLITE_DONE) { printf("step error: %s\n", sqlite3_errmsg(db)); } } while(0); sqlite3_finalize(stmt); } int main() { sqlite3 *db = 0, *db2 = 0; // 修改为完整的URI格式路径 char *label = "file:zmem?mode=memory&cache=shared"; char bf[64]; char *buf = &bf[0]; int ret, i; do { db = getCon(label); if (!db) break; printf("connected\n"); ret = exec(db, "CREATE TABLE MyTable (test VARCHAR(255));"); if (ret != SQLITE_OK) break; for (i = 1; i <= 3; i++) { sprintf(buf,"insert into MyTable (test) values('Hello Row %d')", i); ret = exec(db, buf); if (ret != SQLITE_OK) break; } query(db); db2 = getCon(label); if (!db2) break; printf("connected 2\n"); query(db2); } while(0); if (db) sqlite3_close(db); if (db2) sqlite3_close(db2); return 0; }
运行效果
修改后输出如下:
connected Hello Row 1 Hello Row 2 Hello Row 3 connected 2 Hello Row 1 Hello Row 2 Hello Row 3
注意事项
- 该功能需要SQLite版本 >= 3.7.13
- 所有指向该共享内存库的连接全部关闭后,数据库内容会自动释放
- 多线程并发访问时需要遵循SQLite的线程安全规则,使用FULLMUTEX模式时SQLite会自动处理锁逻辑,不需要额外加锁
内容的提问来源于stack exchange,提问作者Mario Theodoridis
相关产品推荐
相关产品推荐

