Berkeley DB基础教程
一、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位系統上均可運行,已經被好多高端的因特網服務器、臺式機、掌上電腦、機頂盒、網絡交換機以及其他一些應用領域所采用。一旦Berkeley DB被鏈接到應用程序中,終端用戶一般根本感覺不到有一個數據庫系統存在。
? ? 可伸縮(Scalable):這一點表現在很多方面。Database library本身是很精簡的(少于300KB的文本空間),但它能夠管理規模高達256TB的數據庫。它支持高并發度,成千上萬個用戶可同時操縱同一個數據庫。Berkeley DB能以足夠小的空間占用量運行于有嚴格約束的嵌入式系統,也可以在高端服務器上耗用若干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();}}}轉載于:https://www.cnblogs.com/eaglegeek/p/4557923.html
總結
以上是生活随笔為你收集整理的Berkeley DB基础教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QObject 的拷贝构造和赋值操作
- 下一篇: 导航栏动画的效果