当前位置导航:炫浪网>>网络学院>>编程开发>>Visual C#教程

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);
   }
  六、完整操作封装
  
   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)
   {
   this.directory = directory;
   this.dbName = dbName;
  
   Init();
   StreamInit();
   }
  
   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;
   }
   }
  
   private bool iscomit = false;
   public void Commit()
   {
   txn.Commit(Txn.CommitMode.None);
   iscomit = true;
   }
  
   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;
   }
  
   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 bool Remove(IPut put)
   {
   Reset();
  
   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;
   }
   }
  
   public void Dispose()
   {
   if (!iscomit)
   Commit();
   db.Close();
   db.Close();
   }
  
   private void Reset()
   {
   iscomit = false;
   }
  
   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);
   }
  
   private void StreamInit()
   {
   formatter = new BinaryFormatter();
   keyStream = new MemoryStream();
   dataStream = new MemoryStream();
   }
  
   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);
   }
   }
  调用方法:
  首先要有一个写入的实体类,必须可以序列化,并且实现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();
相关内容
赞助商链接