標籤:assert 共用 串連 google 儲存方式 hashmap 網路 終端 學生
一、Berkeley DB的介紹
(1)Berkeley DB是一個嵌入式資料庫,它適合於管理海量的、簡單的資料。如Google使用其來儲存賬戶資訊。Heritrix用其來儲存froniter.
(2)key/value是Berkeley DB用來管理資料的基礎,每一個key/value對代表一條記錄。
(3)Berkeley DB在底層實現採用B樹。可以看成可以儲存大量資料的HashMap。
(4)它是Oracle公司的一個產品,C++版本號碼最新出現,之後JAVA等版本號碼也陸續出現。
它不支援SQL語句。應用程式通過API對資料庫進行操作。
下面內容轉載至百度文庫
Berkeley DB是由美國Sleepycat Software公司開發的一套開放原始碼的嵌入式資料庫的程式庫(database library)。它為應用程式提供可伸縮的、高效能的、有事務保護功能的資料管理服務。
Berkeley DB為資料的存取和管理提供了一組簡潔的函數調用API介面。
它是一個經典的C-library模式的toolkit,為程式猿提供廣泛豐富的函數集,是為應用程式開發人員提供工業級強度的資料庫服務而設計的。
其主要特點例如以下:
嵌入式(Embedded):它直接連結到應用程式中,與應用程式執行於相同的地址空間中,因此。不管是在網路上不同電腦之間還是在同一台電腦的不同進程之間,資料庫操作並不要求進程間通訊。
Berkeley DB為多種程式設計語言提供了API介面,當中包含C、C++、Java、Perl、Tcl、Python和PHP,全部的資料庫操作都在程式庫內部發生。多個進程。或者同一進程的多個線程可同一時候使用資料庫,有如各自單獨使用,底層的服務如加鎖、交易記錄、共用緩衝區管理、記憶體管理等等都由程式庫透明地運行。
輕便靈活(Portable):它能夠執行於差點兒全部的UNIX和Linux系統及其變種系統、Windows作業系統以及多種嵌入式即時作業系統之下。
它在32位和64位系統上均可執行,已經被好多高端的網際網路server、台式機、掌上型電腦、機頂盒、網路交換器以及其它一些應用領域所採用。一旦Berkeley DB被連結到應用程式中,終端使用者一般根本感覺不到有一個資料庫系統存在。
可伸縮(Scalable):這一點表如今非常多方面。Database library本身是非常精簡的(少於300KB的文本空間)。但它可以管理規模高達256TB的資料庫。它支援高並發度。成千上萬個使用者可同一時候操縱同一個資料庫。Berkeley DB能以足夠小的空間佔用量執行於有嚴格約束的嵌入式系統,也可以在高端server上耗用若干GB的記憶體和若干TB的磁碟空間。
Berkeley DB在嵌入式應用中比關聯式資料庫和物件導向資料庫要好。有下面兩點原因:
(1)由於資料庫程式庫同應用程式在同樣的地址空間中執行,所以資料庫操作不須要進程間的通訊。在一台機器的不同進程間或在網路中不同機器間進行進程通訊所花費的開銷。要遠遠大於函數調用的開銷;
(2)由於Berkeley DB對全部操作都使用一組API介面,因此不須要對某種查詢語言進行解析,也不用產生執行計畫,大大提高了執行效.
BerkeleyDB系統結構
Berkeley DB由五個基本的子系統構成.包含: 存取管理子系統、記憶體池管理子系統、事務子系統、鎖子系統以及日誌子系統。
當中存取管理子系統作為Berkeley DB資料庫進程包內部核心組件,而其它子系統都存在於Berkeley DB資料庫進程包的外部。
每一個子系統支援不同的應用層級。
1.資料存取子系統
資料存取(Access Methods)子系統為建立和訪問資料庫檔案提供了多種支援。
Berkeley DB提供了下面四種檔案儲存體方法:
雜湊檔案、B樹、定長記錄(隊列)和變長記錄(基於記錄號的簡單儲存方式)。應用程式能夠從中選擇最適合的檔案組織圖。
程式猿建立表時能夠使用隨意一種結構。而且能夠在同一個應用程式中對不同儲存類型的檔案進行混合操作。
在沒有交易管理的情況下,該子系統中的模組可單獨使用,為應用程式提供高速高效的資料存取服務。
資料存取子系統適用於不需事務僅僅需高速格式檔案訪問的應用。
2.記憶體池管理子系統
記憶體池(Memory pool)子系統對Berkeley DB所使用的共用緩衝區進行有效管理。它同意同一時候訪問資料庫的多個進程或者進程的多個線程共用一個快速緩衝。負責將改動後的頁寫迴文件和為新調入的頁分配記憶體空間。 它也能夠獨立於Berkeley DB系統之外,單獨被應用程式使用。為其自己的檔案和頁分配記憶體空間。
記憶體池管理子系統適用於須要靈活的、面向頁的、緩衝的共用檔案訪問的應用。
3.事務子系統
事務(Transaction)子系統為Berkeley DB提供交易管理功能。
它同意把一組對資料庫的改動看作一個原子單位,這組操作要麼全做,要麼全不做。在預設的情況下。系統將提供嚴格的ACID事務屬性,可是應用程式能夠選擇不使用系統所作的隔離保證。該子系統使用兩段鎖技術和先寫日誌策略來保證資料庫資料的正確性和一致性。
它也能夠被應用程式單獨使用來對其自身的資料更新進行事務保護。事務子系統適用於須要事務保證資料的改動的應用。
4.鎖子系統
鎖(Locking)子系統為Berkeley DB提供鎖機制。為系統提供多使用者讀取和單使用者改動同一對象的共用控制。資料存取子系統可利用該子系統獲得對頁或記錄的讀寫權限。事務子系統利用鎖機制來實現多個事務的並發控制。 該子系統也可被應用程式單獨採用。鎖子系統適用於一個靈活的、高速的、可設定的鎖管理器。
5.日誌子系統
日誌(Logging)子系統採用的是先寫日誌的策略。用於支援事務子系統進行資料恢複。保證資料一致性。它不大可能被應用程式單獨使用,僅僅能作為事務子系統的調用模組。
以上幾部分構成了整個Berkeley DB資料庫系統。各部分的關係例如以所看到的:
在這個模型中,應用程式直接調用的是資料存取子系統和交易管理子系統,這兩個系統進而調用更下層的記憶體管理子系統、鎖子系統和日誌子系統。
因為幾個子系統相對照較獨立,所以應用程式在開始的時候能夠指定哪些資料管理服務將被使用。能夠所有使用,也能夠僅僅用當中的一部分。
比如。假設一個應用程式須要支援多使用者並行作業。但不須要進行交易管理,那它就能夠
僅僅用鎖子系統而不用事務。有些應用程式可能須要高速的、單使用者、沒有交易管理功能的B樹儲存結構。那麼應用程式能夠使鎖子系統和事務子系統失效,這樣就會降低開銷。
BerkeleyDB儲存功能概述
Berkeley DB所管理資料的邏輯組織單位是若干個獨立或有一定關係的資料庫(database),每個資料庫由若干記錄組成,這些記錄全都被表示成(key,value)的形式. 假設把一組相關的(key。value)對也看作一個表的話,那麼每個資料庫僅僅同意存放一個table,這一點不同於一般的關聯式資料庫。實際上,在Berkeley DB中所提到的“資料庫”,相當於一般關聯式資料庫系統中的表。而“key/data”對相當於關聯式資料庫系統中的行(rows)。Berkeley DB不提供關聯式資料庫中列直接訪問的功能,而是在“key/data”對中的data項中通過實際應用來封裝欄位(列)。
在物理組織上,每個資料庫在建立的時候能夠由應用程式依據其資料特點來選擇一種合適的儲存結構。可供選擇的四種檔案儲存體結構各自是:雜湊檔案、B樹、定長記錄(隊列)和變長記錄(基於記錄號的簡單儲存方式)。
一個物理的檔案裡能夠僅僅存放一個單獨的資料庫,也能夠存放若干相關或不相關的資料庫。並且這些資料庫能夠分別採用除隊列之外隨意不同的組織方式,以隊列組織的資料庫僅僅能單獨存放於一個檔案,不能同其它儲存類型混合存放。
一個檔案除了受最大檔案長度和儲存空間的約束之外,理論上能夠儲存隨意多個資料庫。因此系統定位一個資料庫通常須要兩個參數——“檔案名稱”和“資料庫名”。這也是Berkeley DB不同於
一般關聯式資料庫的地方。
Berkeley DB儲存系統為應用程式提供了一系列的介面函數,用於對資料庫的管理和操作。當中包含:
(1)資料庫的建立、開啟、關閉、刪除、重新命名等,以及對資料的檢索和增刪改操作;
(2)提供一些附加的功能,比如讀取資料庫狀態資訊、讀取所在檔案的資訊、讀取所在資料庫環境的資訊、清空資料庫的內容、資料庫的同步備份、版本號碼升級、提示出錯資訊等等;
(3)系統還提供了遊標機制,用於存取和訪問成組的資料,以及對兩個或多個相關資料庫進行關聯和等值串連操作;
(4)系統還給出了一些介面函數用於對存取策略進行最佳化配置,比方應用程式能夠自己設定B樹的排序比較函數、每頁中存放key的最少數目。雜湊桶的填滿因數、雜湊函數、雜湊表最大長度,隊列的最大長度,資料庫存放的位元組順序,
底層儲存頁的大小。記憶體配置函數,快速緩衝的大小,定長記錄的大小和填充位。變長記錄所用的分隔字元等等。
二、Berkeley DB的應用
1、從官方網站http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/overview/index.html下載Berkeley DB的安裝檔案及JAVA開發包。
2、在windows安裝Berkeley DB,一直按下一步就可以。為開發方便,安裝了windows版本號碼,正式執行時應該使用Linux版本號碼。
(設定path時出錯,須要以管理員身份執行安裝程式)。
3、將JAVA開發包中的jar檔案放入buildpath中。主要包含je-6.0.11.jar、JEJConsole.jar、epJEJConsole.jar三個包。
測試程式:
package com.ljh.test;import static org.junit.Assert.*;import org.junit.Before;import org.junit.Test;public class BerkeleyDBUtilTest {private BerkeleyDBUtil dbUtil = null;@Beforepublic void setup() {dbUtil = new BerkeleyDBUtil("D:/tmp");} @Testpublic void testWriteToDatabase() {for (int i = 0; i < 10; i++){dbUtil.writeToDatabase(i+"", "學生"+i, true);}}@Testpublic void testReadFromDatabase() {String value = dbUtil.readFromDatabase("2");assertEquals(value, "學生2");}@Testpublic void testGetEveryItem() {int size = dbUtil.getEveryItem().size();assertEquals(size, 10);}@Testpublic void testDeleteFromDatabase() {dbUtil.deleteFromDatabase("4");assertEquals(9, dbUtil.getEveryItem().size());}public void cleanup() {dbUtil.closeDB();}}
Berkeley DB的基本操作:
包含下面部分
(1)開啟資料庫
(2)向資料庫寫入資料
(3)依據Key值讀取某個資料
(4)讀取全量資料列表
(5)依據Key值刪除某個資料
(6)關閉資料庫
注意:因為各個操作可能相應同一個資料庫,因此是否須要使用單例模式?
package com.ljh.test;import java.io.File;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import com.sleepycat.je.Cursor;import com.sleepycat.je.CursorConfig;import com.sleepycat.je.Database;import com.sleepycat.je.DatabaseConfig;import com.sleepycat.je.DatabaseEntry;import com.sleepycat.je.Environment;import com.sleepycat.je.EnvironmentConfig;import com.sleepycat.je.LockConflictException;import com.sleepycat.je.LockMode;import com.sleepycat.je.OperationStatus;import com.sleepycat.je.Transaction;import com.sleepycat.je.TransactionConfig;public class BerkeleyDBUtil {// 資料庫環境private Environment env = null;// 資料庫private static Database frontierDatabase = null;// 資料庫名private static String dbName = "frontier_database";public BerkeleyDBUtil(String homeDirectory) {// 1、建立EnvironmentConfigEnvironmentConfig envConfig = new EnvironmentConfig();envConfig.setTransactional(true);envConfig.setAllowCreate(true);// 2、使用EnvironmentConfig配置Environmentenv = new Environment(new File(homeDirectory), envConfig);// 3、建立DatabaseConfigDatabaseConfig dbConfig = new DatabaseConfig();dbConfig.setTransactional(true);dbConfig.setAllowCreate(true);// 4、使用Environment與DatabaseConfig開啟DatabasefrontierDatabase = env.openDatabase(null, dbName, dbConfig);}/* * 向資料庫中寫入記錄。並推斷能否夠有反覆資料。 傳入key和value * 若能夠有反覆資料。則直接使用put()就可以。若不能有反覆資料,則使用putNoOverwrite()。 */public boolean writeToDatabase(String key, String value, boolean isOverwrite) {try {// 設定key/value,注意DatabaseEntry內使用的是bytes數組DatabaseEntry theKey = new DatabaseEntry(key.getBytes("UTF-8"));DatabaseEntry theData = new DatabaseEntry(value.getBytes("UTF-8"));OperationStatus status = null;Transaction txn = null;try {// 1、Transaction配置TransactionConfig txConfig = new TransactionConfig();txConfig.setSerializableIsolation(true);txn = env.beginTransaction(null, txConfig);// 2、寫入資料if (isOverwrite) {status = frontierDatabase.put(txn, theKey, theData);} else {status = frontierDatabase.putNoOverwrite(txn, theKey,theData);}txn.commit();if (status == OperationStatus.SUCCESS) {System.out.println("向資料庫" + dbName + "中寫入:" + key + ","+ value);return true;} else if (status == OperationStatus.KEYEXIST) {System.out.println("向資料庫" + dbName + "中寫入:" + key + ","+ value + "失敗,該值已經存在");return false;} else {System.out.println("向資料庫" + dbName + "中寫入:" + key + ","+ value + "失敗");return false;}} catch (LockConflictException lockConflict) {txn.abort();System.out.println("向資料庫" + dbName + "中寫入:" + key + "," + value+ "出現lock異常");return false;}} catch (Exception e) {// 錯誤處理System.out.println("向資料庫" + dbName + "中寫入:" + key + "," + value+ "出現錯誤");return false;}}/* * 從資料庫中讀出資料 傳入key 返回value */public String readFromDatabase(String key) {try {DatabaseEntry theKey = new DatabaseEntry(key.getBytes("UTF-8"));DatabaseEntry theData = new DatabaseEntry();Transaction txn = null;try {// 1、配置 Transaction相關資訊TransactionConfig txConfig = new TransactionConfig();txConfig.setSerializableIsolation(true);txn = env.beginTransaction(null, txConfig);// 2、讀取資料OperationStatus status = frontierDatabase.get(txn, theKey,theData, LockMode.DEFAULT);txn.commit();if (status == OperationStatus.SUCCESS) {// 3、將位元組轉換成Stringbyte[] retData = theData.getData();String value = new String(retData, "UTF-8");System.out.println("從資料庫" + dbName + "中讀取:" + key + ","+ value);return value;} else {System.out.println("No record found for key ‘" + key + "‘.");return "";}} catch (LockConflictException lockConflict) {txn.abort();System.out.println("從資料庫" + dbName + "中讀取:" + key + "出現lock異常");return "";}} catch (UnsupportedEncodingException e) {e.printStackTrace();return "";}}/* * 遍曆資料庫中的全部記錄。返回list */public ArrayList<String> getEveryItem() {// TODO Auto-generated method stubSystem.out.println("===========遍曆資料庫" + dbName + "中的全部資料==========");Cursor myCursor = null;ArrayList<String> resultList = new ArrayList<String>();Transaction txn = null;try {txn = this.env.beginTransaction(null, null);CursorConfig cc = new CursorConfig();cc.setReadCommitted(true);if (myCursor == null)myCursor = frontierDatabase.openCursor(txn, cc);DatabaseEntry foundKey = new DatabaseEntry();DatabaseEntry foundData = new DatabaseEntry();// 使用cursor.getPrev方法來遍曆遊標擷取資料if (myCursor.getFirst(foundKey, foundData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {String theKey = new String(foundKey.getData(), "UTF-8");String theData = new String(foundData.getData(), "UTF-8");resultList.add(theKey);System.out.println("Key | Data : " + theKey + " | " + theData+ "");while (myCursor.getNext(foundKey, foundData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {theKey = new String(foundKey.getData(), "UTF-8");theData = new String(foundData.getData(), "UTF-8");resultList.add(theKey);System.out.println("Key | Data : " + theKey + " | "+ theData + "");}}myCursor.close();txn.commit();return resultList;} catch (UnsupportedEncodingException e) {e.printStackTrace();return null;} catch (Exception e) {System.out.println("getEveryItem處理出現異常");txn.abort();if (myCursor != null) {myCursor.close();}return null;}}/* * 依據key值刪除資料庫中的一條記錄 */public boolean deleteFromDatabase(String key) {boolean success = false;long sleepMillis = 0;for (int i = 0; i < 3; i++) {if (sleepMillis != 0) {try {Thread.sleep(sleepMillis);} catch (InterruptedException e) {e.printStackTrace();}sleepMillis = 0;}Transaction txn = null;try {// 1、使用cursor.getPrev方法來遍曆遊標擷取資料TransactionConfig txConfig = new TransactionConfig();txConfig.setSerializableIsolation(true);txn = env.beginTransaction(null, txConfig);DatabaseEntry theKey;theKey = new DatabaseEntry(key.getBytes("UTF-8"));//2、刪除資料 並提交OperationStatus res = frontierDatabase.delete(txn, theKey);txn.commit();if (res == OperationStatus.SUCCESS) {System.out.println("從資料庫" + dbName + "中刪除:" + key);success = true;return success;} else if (res == OperationStatus.KEYEMPTY) {System.out.println("沒有從資料庫" + dbName + "中找到:" + key + "。
無法刪除");} else {System.out.println("刪除操作失敗,因為" + res.toString());}return false;} catch (UnsupportedEncodingException e) {e.printStackTrace();return false;} catch (LockConflictException lockConflict) {System.out.println("刪除操作失敗,出現lockConflict異常");sleepMillis = 1000;continue;} finally {if (!success) {if (txn != null) {txn.abort();}}}}return false;}public void closeDB() {if (frontierDatabase != null) {frontierDatabase.close();}if (env != null) {env.close();}}}
Berkeley DB基礎教程