C#使用BerkeleyDB操作简介

Berkeley DB是历史悠久的嵌入式数据库系统,主要应用在UNIX/LINUX操作系统上。Berkeley DB的存储的是key/value键值对,可以理解为硬盘上的超级hash表。其可以管理256TB数据,而且能支撑几千个并发访问。目前Berkeley DB有C++版和Java版。所以,我们需要一个访问的中间转换,已经有人发布了C#的API。可以从 Berkeley DB for .NET 上面找到,现在最新版是0.95版本,可以支持4.3和4.5版。本篇将以4.5版做实例。BerkeleyDB的版本可以在http://www.oracle.com/technology/products/berkeley-db/index.html下载,当前最新版本为4.7版。4.5 C++版的Berkeley DB可以在http://www.oracle.com/technology/software/products/berkeley-db/db/index.html这里下载。

 By Birdshover@ 博客园 http://www.cnblogs.com/birdshover/

下载到Berkeley DB for .Net的API——libdb-dotnet_0_95.zip后,就可以开始使用了。首先在libdb-dotnet_0_95.zip解压缩的bin目录找到libdb_dotNET45.dll,这个就是4.5版本使用的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(EnvCreateFlags.None);
Env.OpenFlags envFlags
=
Env.OpenFlags.Create
|
Env.OpenFlags.InitLock
|
Env.OpenFlags.InitLog
|
Env.OpenFlags.InitMPool
|
Env.OpenFlags.InitTxn
|
Env.OpenFlags.Recover;
env.Open(directory, envFlags,
0);
txn
= env.TxnBegin(null, Txn.BeginFlags.None);
db
= env.CreateDatabase(DbCreateFlags.None);
btree
= (DbBTree)db.Open(txn, dbName, null, DbType.BTree, Db.OpenFlags.Create, 0);
}

 

另外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();

keyStream.Position
= 0;
formatter.Serialize(keyStream, put.Key);
DbEntry key
= DbEntry.InOut(keyStream.GetBuffer(), 0, (int)keyStream.Position);
dataStream.Position
= 0;
formatter.Serialize(dataStream, put);
DbEntry data
= DbEntry.InOut(dataStream.GetBuffer(), 0, (int)dataStream.Position);
WriteStatus status
= btree.Put(txn, ref key, ref data);
switch (status)
{
case WriteStatus.Success:
return true;
case WriteStatus.NotFound:
case WriteStatus.KeyExist:
default:
return false;
}
}
上述代码就可以保存键值。显示对键值进行序列化,然后再保存。保存完有三个状态,可以一一处理。
二、数据库的删除
删除最为简单
        public bool Remove(IPut put)
{
keyStream.Position
= 0;
formatter.Serialize(keyStream, put.Key);
DbEntry key
= DbEntry.InOut(keyStream.GetBuffer(), 0, (int)keyStream.Position);
DeleteStatus status
= btree.Delete(txn, ref key);
switch (status)
{
case DeleteStatus.NotFound:
case DeleteStatus.Success:
return true;
case DeleteStatus.KeyEmpty:
default:
return false;
}
}


三、关于添加和删除
添加和删除并没有真正得进行添加和删除。必须执行Commit操作:
        private bool iscomit = false;
public void Commit()
{
txn.Commit(Txn.CommitMode.None);
iscomit
= true;
}

四、寻找键
用键查询值,和hash表一样使用。
        public bool Get(ref IPut put)
{
keyStream.Position
= 0;
formatter.Serialize(keyStream, put.Key);
DbEntry key
= DbEntry.InOut(keyStream.GetBuffer(), 0, (int)keyStream.Position);
dataStream.SetLength(dataStream.Capacity);
DbEntry data
= DbEntry.Out(dataStream.GetBuffer());

while (true)
{
ReadStatus status
= btree.Get(txn, ref key, ref data, DbFile.ReadFlags.None);

switch (status)
{
case ReadStatus.Success:
dataStream.Position
= 0;
dataStream.SetLength(data.Size);
put
= (IPut)formatter.Deserialize(dataStream);
return true;
case ReadStatus.BufferSmall: //扩容
if (key.Buffer.Length < key.Size)
{
keyStream.SetLength(key.Size);
key
= DbEntry.Out(keyStream.GetBuffer());
}
if (data.Buffer.Length < data.Size)
{
dataStream.SetLength(data.Size);
data
= DbEntry.Out(dataStream.GetBuffer());
}
continue;
case ReadStatus.NotFound:
case ReadStatus.KeyEmpty:
default:
return false;
}
}
}

五、遍历
public List<IPut> Find()
{
List
<IPut> custList = new List<IPut>();
using (DbBTreeCursor cursor = btree.OpenCursor(txn, DbFileCursor.CreateFlags.None))
{
IPut cust
= null;
while (GetNextRecord(cursor, ref cust))
custList.Add(cust);
}
return custList;
}

private bool GetNextRecord(DbBTreeCursor cursor, ref IPut cust)
{
ReadStatus status;
keyStream.SetLength(keyStream.Capacity);
dataStream.SetLength(dataStream.Capacity);
DbEntry key
= DbEntry.Out(keyStream.GetBuffer());
DbEntry data
= DbEntry.Out(dataStream.GetBuffer());
do
{
status
= cursor.Get(ref key, ref data, DbFileCursor.GetMode.Next, DbFileCursor.ReadFlags.None);
switch (status)
{
case ReadStatus.NotFound: return false;
case ReadStatus.KeyEmpty: continue; // skip deleted records
case ReadStatus.BufferSmall:
if (key.Buffer.Length < key.Size)
{
keyStream.SetLength(key.Size);
key
= DbEntry.Out(keyStream.GetBuffer());
}
if (data.Buffer.Length < data.Size)
{
dataStream.SetLength(data.Size);
data
= DbEntry.Out(dataStream.GetBuffer());
}
continue;
case ReadStatus.Success:
dataStream.Position
= 0;
dataStream.SetLength(data.Size);
cust
= (IPut)formatter.Deserialize(dataStream);
return true;
default:
return false;
}
}
while (true);
}

六、完整操作封装
代码:BerkeleyDB操作封装
调用方法:
首先要有一个写入的实体类,必须可以序列化,并且实现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 string.Format("ID:{0} Key:{1}", ID, Name);
}

public string Key
{
get { return Name; }
}
}
操作:
           using (BDBManager manager = new BDBManager("db", "db.dat"))
{
bool success = manager.Set(new Item() { ID = 1000, Name = "Test",Text = "213" });
Console.WriteLine(
string.Format("set is {0}", success));
}

using (BDBManager manager = new BDBManager("db", "db.dat"))
{
IPut put
= new Item() { Name = "Test" };
bool success = manager.Get(ref put);
Console.WriteLine(
string.Format("read is {0},item : {1}", success, put.ToString()));
}

using (BDBManager manager = new BDBManager("db", "db.dat"))
{
IPut put
= new Item() { Name = "Test" };
bool success = manager.Remove(put);
Console.WriteLine(
string.Format("remove is {0},item : {1}", success, put.ToString()));
}

using (BDBManager manager = new BDBManager("db", "db.dat"))
{
List
<IPut> list = manager.Find();
foreach (var item in list)
{
Console.WriteLine(item.ToString());
}
}
Console.WriteLine(
"end");
Console.ReadKey();


posted @ 2008-10-07 17:53  Birdshover  阅读(6673)  评论(16编辑  收藏  举报