libleveldb在github上是开源的,获取libleveldb的链接:https://github.com/google/leveldb/tags
leveldb优点:
LevelDB是一个高效的键值嵌入式数据库,1、字符串形式的key-value且长度没有限制。2、数据能持久化存储,同时也能将数据缓存到内存,实现快速读取。3、自定义排序。4、支持简易的操作接口API,如Put、Get、Delete,并支持批量写入。其性能在读写测试中表现出色,对比SQLite3和Kyoto TreeDB有明显优势。适合对性能有高要求的单进程应用场景。
缺点:
缺点在于不支持SQL、多进程和多种数据类型。
代码如下:
leveldb.h
#include <iostream>
#include <string>
#include "leveldb/db.h"
#include "leveldb/write_batch.h"
class CLevel{
public:
static CLevel* GetInstance()
{
std::lock_guard<std::mutex> lock(instanceMt);//如果是在main函数中实现单例模式的话,就不需要加锁,效率会更高
if(pInstance == nullptr)
{
pInstance = new CLevel;
}
return pInstance;
}
int Init();
int GetData(const std::string& key, std::string& strValue);
int GetAllData(std::vector<string, string> vecDBInfo);
int InsertData(const std::string &key, const std::string& value);
int DeleteData(const std::string &key);
private:
CLevel();
~CLevel();
private:
static CLevel*pInstance;
static std::mutex instanceMt;
leveldb::DB* pLevelDb;
leveldb::Options options;
std::mutex levelMt;
};
leveldb.cpp
#include "leveldb.h"
CLevel* CLevel::pInstance = nullptr;
std::mutex CLevel::instanceMt;
int CLevel::Init()
{
options.create_if_missing = true;
//options.error_if_exists=true;//true:目录存在则返回错误.默认是false
leveldb::Status status = leveldb::DB::Open(options, "levelDb", &pLevelDb);
if (!status.ok())
{
std::cout << "Init FilePath LevelDB Error:" << status.ToString() << std::endl;
pLevelDb = NULL;
exit(-1);
}
std::cout << "Open FilePath LevelDB successfully" << std::endl;
return 0;
}
int CLevel::GetData(const std::string & key, std::string & strValue)
{
std::lock_guard<std::mutex> lock(levelMt);
if (!pLevelDb)
{
std::cout << "Get All File Path From LevelDB Failed.LevelDB pointer is NULL" << std::endl;
return -1;
}
leveldb::Status status;
status = pLevelDb->Get(leveldb::ReadOptions(), key, &strValue);
if (!status.ok())
{
std::cout << "From LevelDB Get key:" << key << " Data Failed." << status.ToString() << std::endl;
return -2;
}
return 0;
}
int CLevel::GetAllData(std::vector<string, string> vecDBInfo)
{
std::lock_guard<std::mutex> lock(levelMt);
if (!pLevelDb)
{
std::cout << "Get All File Path From LevelDB Failed.LevelDB pointer is NULL" << std::endl;
return -1;
}
leveldb::Iterator* it = pLevelDb->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next())
{
vecDBInfo.push_back(t->key().ToString(), it->value().ToString());
}
}
}
int CLevel::InsertData(const std::string & key, const std::string & value)
{
std::lock_guard<std::mutex> lock(levelMt);
if (!pLevelDb)
{
std::cout << "Insert Data To LevelDB Failed. LevelDB poionter is NULL" << std::endl;
return -1;
}
leveldb::Status status;
leveldb::WriteOptions write_options;
//write_options.sync = true; //true:写同步。默认是false,写异步
status = pLevelDb->Put(write_options, key, value);
if (!status.ok())
{
std::cout << "Insert Data to LevelDB Failed:" <<
status.ToString() << std::endl;
return -2;
}
return 0;
}
int CLevel::DeleteData(const std::string & key)
{
std::lock_guard<std::mutex> lock(levelMt);
if (!pLevelDb)
{
std::cout << "Delete Statistics Data From LevelDB Failed.LevelDB pointer is NULL" << std::endl;
return -1;
}
leveldb::Status status;
status = pLevelDb->Delete(leveldb::WriteOptions(), key);
if(!status.ok())
{
std::cout << "Delete Statistics Data From LevelDB Failed:" << status.ToString()<< std::endl;
return -2;
}
return 0;
}
int CLevel::UpdateData(const std::string & key, const std::string& value)
{
//std::lock_guard<std::mutex> lock(levelMt);这里就不要加锁了,下面的获取、删除、插入接口都有加锁,这里再加锁就会死锁。
std::string strValue;
if (0 == GetData(key, strValue))
{
std::cout << "Last UpdateTime:" <<strValue << " This UpdateTime:" << value <<std::endl;
}
DeleteData(key);
int ret = insertData(key, value);
return ret;
}
leveldb初始化:
leveldb 数据库都有一个名字,该名字对应文件系统上的一个目录,该数据库内容全都存在该目录下,类似如下代码就是开一个数据库,其数据库路径为./leveldb,(若没有这个路径则)必要时创建数据库:
如果想在数据库已存在的时候触发一个异常,将下面这行配置加到 leveldb::DB::Open 调用之前:
options.error_if_exists=true;
leveldb写操作:
默认情况下,leveldb 每个写操作都是异步的:进程把要写的内容丢给操作系统后立即返回,从操作系统内存到底层持久化存储的传输是异步进行的。
也可以为某个特定的写操作打开同步标识:write_options.sync = true,以等到数据真正被记录到持久化存储后再返回。异步写通常比同步写快 1000 倍。异步写的缺点是,一旦机器崩溃可能会导致最后几个更新操作丢失。注意,仅仅是写进程崩溃(而非机器重启)不会造成任何损失,因为哪怕 sync 标识为 false,在进程退出之前,写操作也已经从进程内存推到了操作系统。