備注學院

          LuLu

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            5 隨筆 :: 50 文章 :: 16 評論 :: 0 Trackbacks

          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();
          posted on 2008-11-13 10:37 smildlzj 閱讀(338) 評論(0)  編輯  收藏 所屬分類: 數據庫C#
          主站蜘蛛池模板: 金门县| 土默特右旗| 四子王旗| 屯留县| 武隆县| 张北县| 朝阳市| 吴川市| 聂荣县| 买车| 博乐市| 民乐县| 康乐县| 富民县| 杭州市| 出国| 襄樊市| 达拉特旗| 通化县| 双峰县| 佳木斯市| 左贡县| 七台河市| 独山县| 北安市| 万宁市| 莫力| 靖宇县| 郎溪县| 东兰县| 新乐市| 富阳市| 福建省| 天台县| 博爱县| 黎川县| 常州市| 阿鲁科尔沁旗| 洛隆县| 上虞市| 郎溪县|