sqlite記憶體資料庫和檔案資料庫的同步
阿新 • • 發佈:2019-02-17
由於sqlite對多程序操作支援效果不太理想,在專案中,為了避免頻繁讀寫 檔案資料庫帶來的效能損耗,我們可以採用操作sqlite記憶體資料庫,並將記憶體資料庫定時同步到檔案資料庫中的方法。
實現思路如下:
1、建立檔案資料庫;
2、建立記憶體資料庫(檔案資料庫、記憶體資料庫的內幕表結構需要一致);
3、在記憶體資料庫中attach檔案資料庫,這樣可以保證檔案資料庫中的內容在記憶體資料庫中可見;
4、對於insert、select操作,在記憶體資料庫中完成,對於delete、update操作,需要同時訪問記憶體、檔案資料庫;
5、定時將記憶體資料庫中的內容flush到檔案資料庫。
通過sqlite的cAPI實現程式碼如下:
const char* file_database_path = "/home/tom/test/database/filedb"; //檔案資料庫存放路徑 const char* sql_create_data = "CREATE TABLE testinfo (id TEXT PRIMARY KEY, message TEXT, offset INTEGER, timestamp INTEGER);"; const char* sql_insert_data = "INSERT OR REPLACE INTO MAIN.testinfo VALUES('%s', '%s', %d, %d);"; const char* sql_delete_data = "DELETE FROM MAIN.testinfo WHERE id = '%s'; DELETE FROM filedb.testinfo WHERE id = '%s';"; //刪除資料庫,需同時刪除記憶體、檔案資料庫中的內容 const char* sql_update_data = "UPDATE MAIN.testinfo SET message = '%s', offset = %d, timestamp = %d where id = '%s'; UPDATE filedb.testinfo SET message = '%s', offset = %d, timestamp = %d where id = '%s';";//更新資料庫,需同時更新記憶體、檔案資料庫中的內容 const char* sql_search_data = "SELECT * FROM MAIN.testinfo WHERE timestamp BETWEEN %d AND %d union SELECT * FROM testdb.testinfo WHERE timestamp BETWEEN %d AND %d;"; //查詢資料庫,將記憶體、檔案資料庫中查找出的內容合併 const char* sql_transfer_data = "INSERT OR REPLACE INTO filedb.testinfo SELECT * FROM testinfo;"; //將記憶體資料庫中的資訊同步到檔案資料庫中 const char* sql_delete_memory_table = "DELETE FROM testinfo;"; //記憶體資料庫中的內容同步結束後,清空 int InsertRecord(DATA_TYPE type, const char* id, const char* message, int offset, int timestamp) { int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; time_t insertTimestamp = 0; snprintf(sqlcmd, sizeof(sqlcmd), sql_insert_data, id, message, offset, timestamp); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't add record to memory database %s, sqlcmd=%s, err:%s\n", map_data_table[type].data_table_name, sqlcmd, errMsg); return -1; } return 0; } int UpdateRecord(DATA_TYPE type, const char* id, const char* message, int offset, int timestamp) { int rc = 0; char* errMsg = NULL; char sqlCmd[512] = {0}; snprintf(sqlCmd, sizeof(sqlCmd), sql_update_data, message, offset, timestamp, id, message, offset, timestamp, id); rc = sqlite3_exec(memdb, sqlCmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't update record %s:%s\n", map_data_table[type].data_table_name, errMsg); return -1; } return 0; } int DeleteRecord(DATA_TYPE type, const char* id) { int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; snprintf(sqlcmd, sizeof(sqlcmd), sql_delete_data, id, id); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't delete record %s:%s\n", map_data_table[type].data_table_name, errMsg); return -1; } return 0; } int QueryMessage(DATA_TYPE type, int startTime, int endTime) { int rc = 0; char *errMsg = NULL; sqlite3 *filedb = NULL; char** pRecord = NULL; int row = 0; int column = 0; char sqlcmd[512] = {0}; if (type > VEP_NELEMS(map_data_table) || type < 0) { return -1; } rc = sqlite3_open(file_database_path, &filedb); if (SQLITE_OK != rc) { fprintf(stderr, "cat't open database:%s\n", sqlite3_errmsg(filedb)); sqlite3_close(filedb); return -1; } snprintf(sqlcmd, sizeof(sqlcmd), sql_search_data, startTime, endTime, startTime, endTime); rc = sqlite3_get_table(filedb, sqlcmd, &pRecord, &row, &column, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't get table from%s:%s\n", map_data_table[type].data_table_name, errMsg); return -1; } int i; printf("row = %d, column = %d\n", row, column); for(i = 0; i < 2*column; i++) { printf("%s ", pRecord[i]); } printf("\n"); return 0; } //定時呼叫此函式將記憶體資料中的內容同步到檔案資料庫 int Flush(){ int i = 0; int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; snprintf(sqlcmd, sizeof(sqlcmd), sql_transfer_data); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't transfer memory database %s to file databasede:%s\n", map_data_table[i].data_table_name, sqlite3_errmsg(memdb)); sqlite3_close(memdb); return -1; } snprintf(sqlcmd, sizeof(sqlcmd), sql_delete_memory_table); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); return 0; } //建立檔案資料庫 int CreateDbOnFile() { sqlite3 *db = NULL; int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; int i = 0; rc = sqlite3_open(file_database_path, &db); if (SQLITE_OK != rc) { fprintf(stderr, "cat't open database:%s\n", sqlite3_errmsg(db)); sqlite3_close(db); return -1; } snprintf(sqlcmd, sizeof(sqlcmd), sql_create_data); rc = sqlite3_exec(db, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't create file database testinfo:%s\n", errMsg); sqlite3_close(db); return -1; } sqlite3_close(db); return 0; } //建立記憶體資料庫 int CreateDbOnMemery() { int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; int i = 0; rc = sqlite3_open(":memory:", &memdb); if (SQLITE_OK != rc) { fprintf(stderr, "cat't open database:%s\n", sqlite3_errmsg(memdb)); sqlite3_close(memdb); return -1; } snprintf(sqlcmd, sizeof(sqlcmd), sql_create_data); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't create memory database %s\n", errMsg); sqlite3_close(memdb); return -1; } return 0; } //解綁資料庫 int DetachDb() { int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; snprintf(sqlcmd, sizeof(sqlcmd), "DETACH '%s'", "filedb"); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "detach file database failed:%s:%s\n", file_database_path, errMsg); sqlite3_close(memdb); return -1; } return 0; } //將檔案資料庫作為記憶體資料庫的附加資料庫 int AttachDb() { int rc = 0; char* errMsg = NULL; char sqlcmd[512] = {0}; snprintf(sqlcmd, sizeof(sqlcmd), "ATTACH '%s' AS %s", file_database_path, "filedb"); rc = sqlite3_exec(memdb, sqlcmd, NULL, NULL, &errMsg); if (SQLITE_OK != rc) { fprintf(stderr, "cat't attach database %s:%s\n", file_database_path, errMsg); sqlite3_close(memdb); return -1; } return 0; } //初始化資料庫,分別建立檔案資料庫、記憶體資料庫並把檔案資料庫attach到記憶體資料庫上 int InitSqliteDb() { int retval = 0; retval = CreateDbOnFile(); if (retval != 0) { return retval; } retval = CreateDbOnMemery(); if (retval != 0) { return retval; } retval = AttachDb(); if (retval != 0) { return retval; } return 0; }