Berkeley DB是历史悠久的嵌入式数据库系统
主要应用在UNIX/LINUX操作系统上
Berkeley DB的存储的是key/value键值对
可以理解为硬盘上的超级hash表
其可以管理
TB数据
而且能支撑几千个并发访问
目前Berkeley DB有C++版和Java版
所以
我们需要一个访问的中间转换
已经有人发布了C#的API
可以从 Berkeley DB for
NET 上面找到
现在最新版是
版本
可以支持
和
版
本篇将以
版做实例
BerkeleyDB的版本可以在
db/l下载
当前最新版本为
版
C++版的Berkeley DB可以在
db/db/l这里下载
By Birdshover@ 博客园
下载到Berkeley DB for Net的API——libdbdotnet__zip后就可以开始使用了首先在libdbdotnet__zip解压缩的bin目录找到libdb_dotNETdll这个就是版本使用的dll新建项目引用这个dll注意自己编译源码可能会编译不过主要是因为里面一些委托和委托的参数可见性不一致造成的把那些参数用到的class 或者struct都调成public即可
BerkeleyDB的数据库操作需要借助DbBTree类因此需要先得到DbBTree的实例但是DbBTree类会对其它几个类有依赖必须依赖其它几个类才能创建
下面代码就是初始化得到DbBTree实例的一个过程
/// <summary>
/// 数据库目录
/// </summary>
private string directory;
/// <summary>
/// 数据库文件名
/// </summary>
private string dbName;
private DbBTree btree;
private Txn txn;
private Db db;
private Env env;
/// <summary>
/// 初始化
/// </summary>
private void Init()
{
env = new Env(EnvCreateFlagsNone);
EnvOpenFlags envFlags =
EnvOpenFlagsCreate |
EnvOpenFlagsInitLock |
EnvOpenFlagsInitLog |
EnvOpenFlagsInitMPool |
EnvOpenFlagsInitTxn |
EnvOpenFlagsRecover;
envOpen(directory envFlags );
txn = envTxnBegin(null TxnBeginFlagsNone);
db = envCreateDatabase(DbCreateFlagsNone);
btree = (DbBTree)dbOpen(txn dbName null DbTypeBTree DbOpenFlagsCreate );
}
另外Berkeley DB数据库的操作需要借助于序列化
/// <summary>
/// 二进制序列化
/// </summary>
private BinaryFormatter formatter;
/// <summary>
/// 键内存流
/// </summary>
private MemoryStream keyStream;
/// <summary>
/// 内容内存流
/// </summary>
private MemoryStream dataStream;
private void StreamInit()
{
formatter = new BinaryFormatter();
keyStream = new MemoryStream();
dataStream = new MemoryStream();
}
Berkeley DB是键值数据库因此定义一个获取键接口
public interface IPut
{
string Key { get; }
}
一数据库的保存与更新
public bool Set(IPut put)
{
Reset();
keyStreamPosition = ;
formatterSerialize(keyStream putKey);
DbEntry key = DbEntryInOut(keyStreamGetBuffer() (int)keyStreamPosition);
dataStreamPosition = ;
formatterSerialize(dataStream put);
DbEntry data = DbEntryInOut(dataStreamGetBuffer() (int)dataStreamPosition);
WriteStatus status = btreePut(txn ref key ref data);
switch (status)
{
case WriteStatusSuccess:
return true;
case WriteStatusNotFound:
case WriteStatusKeyExist:
default:
return false;
}
}
上述代码就可以保存键值显示对键值进行序列化然后再保存保存完有三个状态可以一一处理
二数据库的删除
删除最为简单
public bool Remove(IPut put)
{
keyStreamPosition = ;
formatterSerialize(keyStream putKey);
DbEntry key = DbEntryInOut(keyStreamGetBuffer() (int)keyStreamPosition);
DeleteStatus status = btreeDelete(txn ref key);
switch (status)
{
case DeleteStatusNotFound:
case DeleteStatusSuccess:
return true;
case DeleteStatusKeyEmpty:
default:
return false;
}
}
三关于添加和删除
添加和删除并没有真正得进行添加和删除必须执行Commit操作
private bool iscomit = false;
public void Commit()
{
txnCommit(TxnCommitModeNone);
iscomit = true;
}
四寻找键
用键查询值和hash表一样使用
public bool Get(ref IPut put)
{
keyStreamPosition = ;
formatterSerialize(keyStream putKey);
DbEntry key = DbEntryInOut(keyStreamGetBuffer() (int)keyStreamPosition);
dataStreamSetLength(dataStreamCapacity);
DbEntry data = DbEntryOut(dataStreamGetBuffer());
while (true)
{
ReadStatus status = btreeGet(txn ref key ref data DbFileReadFlagsNone);
switch (status)
{
case ReadStatusSuccess:
dataStreamPosition = ;
dataStreamSetLength(dataSize);
put = (IPut)formatterDeserialize(dataStream);
return true;
case ReadStatusBufferSmall: //扩容
if (keyBufferLength < keySize)
{
keyStreamSetLength(keySize);
key = DbEntryOut(keyStreamGetBuffer());
}
if (dataBufferLength < dataSize)
{
dataStreamSetLength(dataSize);
data = DbEntryOut(dataStreamGetBuffer());
}
continue;
case ReadStatusNotFound:
case ReadStatusKeyEmpty:
default:
return false;
}
}
}
五遍历
public List<IPut> Find()
{
List<IPut> custList = new List<IPut>();
using (DbBTreeCursor cursor = btreeOpenCursor(txn DbFileCursorCreateFlagsNone))
{
IPut cust = null;
while (GetNextRecord(cursor ref cust))
custListAdd(cust);
}
return custList;
}
private bool GetNextRecord(DbBTreeCursor cursor ref IPut cust)
{
ReadStatus status;
keyStreamSetLength(keyStreamCapacity);
dataStreamSetLength(dataStreamCapacity);
DbEntry key = DbEntryOut(keyStreamGetBuffer());
DbEntry data = DbEntryOut(dataStreamGetBuffer());
do
{
status = cursorGet(ref key ref data DbFileCursorGetModeNext DbFileCursorReadFlagsNone);
switch (status)
{
case ReadStatusNotFound: return false;
case ReadStatusKeyEmpty: continue; // skip deleted records
case ReadStatusBufferSmall:
if (keyBufferLength < keySize)
{
keyStreamSetLength(keySize);
key = DbEntryOut(keyStreamGetBuffer());
}
if (dataBufferLength < dataSize)
{
dataStreamSetLength(dataSize);
data = DbEntryOut(dataStreamGetBuffer());
}
continue;
case ReadStatusSuccess:
dataStreamPosition = ;
dataStreamSetLength(dataSize);
cust = (IPut)formatterDeserialize(dataStream);
return true;
default:
return false;
}
} while (true);
}
六完整操作封装
public interface IPut
{
string Key { get; }
}
public class BDBManager : IDisposable
{
/// <summary>
/// 数据库目录
/// </summary>
private string directory;
/// <summary>
/// 数据库文件名
/// </summary>
private string dbName;
private DbBTree btree;
private Txn txn;
private Db db;
private Env env;
/// <summary>
/// 二进制序列化
/// </summary>
private BinaryFormatter formatter;
/// <summary>
/// 键内存流
/// </summary>
private MemoryStream keyStream;
/// <summary>
/// 内容内存流
/// </summary>
private MemoryStream dataStream;
public BDBManager(string directory string dbName)
{
thisdirectory = directory;
thisdbName = dbName;
Init();
StreamInit();
}
public bool Set(IPut put)
{
Reset();
keyStreamPosition = ;
formatterSerialize(keyStream putKey);
DbEntry key = DbEntryInOut(keyStreamGetBuffer() (int)keyStreamPosition);
dataStreamPosition = ;
formatterSerialize(dataStream put);
DbEntry data = DbEntryInOut(dataStreamGetBuffer() (int)dataStreamPosition);
WriteStatus status = btreePut(txn ref key ref data);
switch (status)
{
case WriteStatusSuccess:
return true;
case WriteStatusNotFound:
case WriteStatusKeyExist:
default:
return false;
}
}
private bool iscomit = false;
public void Commit()
{
txnCommit(TxnCommitModeNone);
iscomit = true;
}
public List<IPut> Find()
{
List<IPut> custList = new List<IPut>();
using (DbBTreeCursor cursor = btreeOpenCursor(txn DbFileCursorCreateFlagsNone))
{
IPut cust = null;
while (GetNextRecord(cursor ref cust))
custListAdd(cust);
}
return custList;
}
public bool Get(ref IPut put)
{
keyStreamPosition = ;
formatterSerialize(keyStream putKey);
DbEntry key = DbEntryInOut(keyStreamGetBuffer() (int)keyStreamPosition);
dataStreamSetLength(dataStreamCapacity);
DbEntry data = DbEntryOut(dataStreamGetBuffer());
while (true)
{
ReadStatus status = btreeGet(txn ref key ref data DbFileReadFlagsNone);
switch (status)
{
case ReadStatusSuccess:
dataStreamPosition = ;
dataStreamSetLength(dataSize);
put = (IPut)formatterDeserialize(dataStream);
return true;
case ReadStatusBufferSmall: //扩容
if (keyBufferLength < keySize)
{
keyStreamSetLength(keySize);
key = DbEntryOut(keyStreamGetBuffer());
}
if (dataBufferLength < dataSize)
{
dataStreamSetLength(dataSize);
data = DbEntryOut(dataStreamGetBuffer());
}
continue;
case ReadStatusNotFound:
case ReadStatusKeyEmpty:
default:
return false;
}
}
}
public bool Remove(IPut put)
{
Reset();
keyStreamPosition = ;
formatterSerialize(keyStream putKey);
DbEntry key = DbEntryInOut(keyStreamGetBuffer() (int)keyStreamPosition);
DeleteStatus status = btreeDelete(txn ref key);
switch (status)
{
case DeleteStatusNotFound:
case DeleteStatusSuccess:
return true;
case DeleteStatusKeyEmpty:
default:
return false;
}
}
public void Dispose()
{
if (!iscomit)
Commit();
dbClose();
dbClose();
}
private void Reset()
{
iscomit = false;
}
private void Init()
{
env = new Env(EnvCreateFlagsNone);
EnvOpenFlags envFlags =
EnvOpenFlagsCreate |
EnvOpenFlagsInitLock |
EnvOpenFlagsInitLog |
EnvOpenFlagsInitMPool |
EnvOpenFlagsInitTxn |
EnvOpenFlagsRecover;
envOpen(directory envFlags );
txn = envTxnBegin(null TxnBeginFlagsNone);
db = envCreateDatabase(DbCreateFlagsNone);
btree = (DbBTree)dbOpen(txn dbName null DbTypeBTree DbOpenFlagsCreate );
}
private void StreamInit()
{
formatter = new BinaryFormatter();
keyStream = new MemoryStream();
dataStream = new MemoryStream();
}
private bool GetNextRecord(DbBTreeCursor cursor ref IPut cust)
{
ReadStatus status;
keyStreamSetLength(keyStreamCapacity);
dataStreamSetLength(dataStreamCapacity);
DbEntry key = DbEntryOut(keyStreamGetBuffer());
DbEntry data = DbEntryOut(dataStreamGetBuffer());
do
{
status = cursorGet(ref key ref data DbFileCursorGetModeNext DbFileCursorReadFlagsNone);
switch (status)
{
case ReadStatusNotFound: return false;
case ReadStatusKeyEmpty: continue; // skip deleted records
case ReadStatusBufferSmall:
if (keyBufferLength < keySize)
{
keyStreamSetLength(keySize);
key = DbEntryOut(keyStreamGetBuffer());
}
if (dataBufferLength < dataSize)
{
dataStreamSetLength(dataSize);
data = DbEntryOut(dataStreamGetBuffer());
}
continue;
case ReadStatusSuccess:
dataStreamPosition = ;
dataStreamSetLength(dataSize);
cust = (IPut)formatterDeserialize(dataStream);
return true;
default:
return false;
}
} while (true);
}
}
调用方法
首先要有一个写入的实体类必须可以序列化并且实现IPut接口
[Serializable()]
class Item : IPut
{
public string Name { get; set; }
public string Text { get; set; }
public int ID { get; set; }
public override string ToString()
{
return stringFormat(ID:{} Key:{} ID Name);
}
public string Key
{
get { return Name; }
}
}
操作
using (BDBManager manager = new BDBManager(db dbdat))
{
bool success = managerSet(new Item() { ID = Name = TestText = });
ConsoleWriteLine(stringFormat(set is {} success));
}
using (BDBManager manager = new BDBManager(db dbdat))
{
IPut put = new Item() { Name = Test };
bool success = managerGet(ref put);
ConsoleWriteLine(stringFormat(read is {}item : {} success putToString()));
}
using (BDBManager manager = new BDBManager(db dbdat))
{
IPut put = new Item() { Name = Test };
bool success = managerRemove(put);
ConsoleWriteLine(stringFormat(remove is {}item : {} success putToString()));
}
using (BDBManager manager = new BDBManager(db dbdat))
{
List<IPut> list = managerFind();
foreach (var item in list)
{
ConsoleWriteLine(itemToString());
}
}
ConsoleWriteLine(end);
ConsoleReadKey();