目前在做本地緩存時常用的方式是用sqlite作爲本地緩存數據庫,緩存使用的場景很多,每次都設計表就變成一件很麻煩的事情,而且很多場景就只是用來記錄一些配置信息,所以採用key-value這種接口去封裝sqlite就是一種很好的方式。
接口:
#include <string>
class LocalStorage
{
public:
SINGLETON_DEFINE(LocalStorage);
LocalStorage();
~LocalStorage();
public:
bool Load(std::string sBusiness, std::string key, __int32& value);
bool Load(std::string sBusiness, std::string key, __int64& value);
bool Load(std::string sBusiness, std::string key, std::string& value);
bool Load(std::string sBusiness, std::vector<std::pair<std::string, std::string>>& keyValue);
bool Save(std::string sBusiness, std::string key, __int32 value);
bool Save(std::string sBusiness, std::string key, __int64 value);
bool Save(std::string sBusiness, std::string key, std::string value);
bool Remove(std::string sBusiness, std::string key);
bool Remove(std::string sBusiness);
};
load方法共有4個重載方法1,2這兩個數值型底層調用的還是第三個string型的方法,後面只是將string轉爲了數值型。
load的第四個方法是將整個業務的所有key-value取出。
Save共三個方法,1,2的數值型接口底層也是調用的第三個string型的。
Remove兩個方法,第一個將對應key的key-value記錄刪除,第二個刪除整個業務緩存。
第一個參數業務內部對應的是一張表,key-value對應表中的記錄。每一條記錄都是固定的key-value格式。
實現:
#include "localstorage.h"
#include "db/db_sqlite3.h"
#include "base/sqllite/db_sqlite3.h"
#include <ShlObj.h>
#include <Shlwapi.h>
namespace{
ndb::SQLiteDB db_;
bool OpenDB()
{
char szPath[MAX_PATH] = { 0 };
::SHGetSpecialFolderPathA(nullptr, szPath, CSIDL_LOCAL_APPDATA, FALSE);
::PathAppendA(szPath, "localstorage.db");
bool result = db_.Open(szPath,
"",
ndb::SQLiteDB::modeReadWrite | ndb::SQLiteDB::modeCreate | ndb::SQLiteDB::modeSerialized
);
return result;
}
bool CloseDB()
{
return db_.Close();
}
bool CreateTable(std::string sBusiness)
{
std::string sSqlCreate = "CREATE TABLE IF NOT EXISTS ";
sSqlCreate += sBusiness;
sSqlCreate += "(key TEXT PRIMARY KEY, value TEXT)";
int dbresult = SQLITE_OK;
dbresult |= db_.Query(sSqlCreate.c_str());
bool no_error = dbresult == SQLITE_OK;
return no_error;
}
}
LocalStorage::LocalStorage()
{
OpenDB();
}
LocalStorage::~LocalStorage()
{
CloseDB();
}
bool LocalStorage::Load(std::string sBusiness, std::string key, __int32& value)
{
std::string sValue;
if (Load(sBusiness, key, sValue))
{
value = std::stoi(sValue);
}
return true;
}
bool LocalStorage::Load(std::string sBusiness, std::string key, __int64& value)
{
std::string sValue;
if (Load(sBusiness, key, sValue))
{
value = std::stoll(sValue);
}
return true;
}
bool LocalStorage::Load(std::string sBusiness, std::string key, std::string& value)
{
ndb::SQLiteStatement stmt;
std::string sSqlSelect = "SELECT * FROM ";
sSqlSelect += sBusiness;
sSqlSelect += " WHERE key=?;";
db_.Query(stmt, sSqlSelect.c_str());
stmt.BindText(1, key.c_str(), key.size());
int32_t result = stmt.NextRow();
if (result == SQLITE_ROW)
{
value = stmt.GetTextField(1);
return true;
}
return false;
}
bool LocalStorage::Load(std::string sBusiness, std::vector<std::pair<std::string, std::string>>& keyValue)
{
ndb::SQLiteStatement stmt;
std::string sSqlSelect = "SELECT * FROM ";
sSqlSelect += sBusiness;
sSqlSelect += ";";
int result = SQLITE_OK;
result |= db_.Query(stmt, sSqlSelect.c_str());
if (SQLITE_OK == result)
{
result = stmt.NextRow();
while (result == SQLITE_ROW)
{
const char* sKey = stmt.GetTextField(0);
const char* sValue = stmt.GetTextField(1);
if (nullptr != sKey && nullptr != sValue)
{
keyValue.push_back(std::make_pair(sKey, sValue));
}
result = stmt.NextRow();
}
return true;
}
return false;
}
bool LocalStorage::Save(std::string sBusiness, std::string key, __int32 value)
{
std::string sValue = std::to_string(value);
return Save(sBusiness, key, sValue);
}
bool LocalStorage::Save(std::string sBusiness, std::string key, __int64 value)
{
std::string sValue = std::to_string(value);
return Save(sBusiness, key, sValue);
}
bool LocalStorage::Save(std::string sBusiness, std::string key, std::string value)
{
if (CreateTable(sBusiness))
{
std::string sSqlInsert = "INSERT OR REPLACE into ";
sSqlInsert += sBusiness;
sSqlInsert += " (key,value) values (?,?);";
ndb::SQLiteStatement stmt;
db_.Query(stmt, sSqlInsert.c_str());
stmt.BindText(1, key.c_str(), key.size());
stmt.BindText(2, value.c_str(), value.size());
int32_t result = stmt.NextRow();
bool no_error = result == SQLITE_OK || result == SQLITE_ROW || result == SQLITE_DONE;
if (no_error)
{
return true;
}
}
return false;
}
bool LocalStorage::Remove(std::string sBusiness, std::string key)
{
std::string sSqlDeleteRecord = "DELETE FROM ";
sSqlDeleteRecord += sBusiness;
sSqlDeleteRecord += " WHERE key=?;";
ndb::SQLiteStatement stmt;
int dbresult = SQLITE_OK;
dbresult |= db_.Query(stmt, sSqlDeleteRecord.c_str());
stmt.BindText(1, key.c_str());
int32_t result = stmt.NextRow();
return (result == SQLITE_OK || result == SQLITE_ROW || result == SQLITE_DONE);
}
bool LocalStorage::Remove(std::string sBusiness)
{
std::string sSqlDropTable = "DROP TABLE ";
sSqlDropTable += sBusiness;
sSqlDropTable += ";";
int dbresult = SQLITE_OK;
dbresult |= db_.Query(sSqlDropTable.c_str());
return dbresult == SQLITE_OK;
}