目前在做本地缓存时常用的方式是用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;
}