Berkeley DB基础教程
一、Berkeley DB的介紹
(1)Berkeley DB是一個嵌入式數(shù)據(jù)庫,它適合于管理海量的、簡單的數(shù)據(jù)。如Google使用其來保存賬戶信息,Heritrix用其來保存froniter.
(2)key/value是Berkeley DB用來管理數(shù)據(jù)的基礎,每個key/value對代表一條記錄。
(3)Berkeley DB在底層實現(xiàn)采用B樹,可以看成能夠存儲大量數(shù)據(jù)的HashMap。
(4)它是Oracle公司的一個產(chǎn)品,C++版本最新出現(xiàn),之后JAVA等版本也陸續(xù)出現(xiàn)。它不支持SQL語句,應用程序通過API對數(shù)據(jù)庫進行操作。
以下內(nèi)容轉(zhuǎn)載至百度文庫
Berkeley DB是由美國Sleepycat Software公司開發(fā)的一套開放源碼的嵌入式數(shù)據(jù)庫的程序庫(database library),它為應用程序提供可伸縮的、高性能的、有事務保護功能的數(shù)據(jù)管理服務。Berkeley DB為數(shù)據(jù)的存取和管理提供了一組簡潔的函數(shù)調(diào)用API接口。
? ? 它是一個經(jīng)典的C-library模式的toolkit,為程序員提供廣泛豐富的函數(shù)集,是為應用程序開發(fā)者提供工業(yè)級強度的數(shù)據(jù)庫服務而設計的。其主要特點如下:
? ? 嵌入式(Embedded):它直接鏈接到應用程序中,與應用程序運行于同樣的地址空間中,因此,無論是在網(wǎng)絡上不同計算機之間還是在同一臺計算機的不同進程之間,數(shù)據(jù)庫操作并不要求進程間通訊。
? ? Berkeley DB為多種編程語言提供了API接口,其中包括C、C++、Java、Perl、Tcl、Python和PHP,所有的數(shù)據(jù)庫操作都在程序庫內(nèi)部發(fā)生。多個進程,或者同一進程的多個線程可同時使用數(shù)據(jù)庫,有如各自單獨使用,底層的服務如加鎖、事務日志、共享緩沖區(qū)管理、內(nèi)存管理等等都由程序庫透明地執(zhí)行。
? ? 輕便靈活(Portable):它可以運行于幾乎所有的UNIX和Linux系統(tǒng)及其變種系統(tǒng)、Windows操作系統(tǒng)以及多種嵌入式實時操作系統(tǒng)之下。它在32位和64位系統(tǒng)上均可運行,已經(jīng)被好多高端的因特網(wǎng)服務器、臺式機、掌上電腦、機頂盒、網(wǎng)絡交換機以及其他一些應用領域所采用。一旦Berkeley DB被鏈接到應用程序中,終端用戶一般根本感覺不到有一個數(shù)據(jù)庫系統(tǒng)存在。
? ? 可伸縮(Scalable):這一點表現(xiàn)在很多方面。Database library本身是很精簡的(少于300KB的文本空間),但它能夠管理規(guī)模高達256TB的數(shù)據(jù)庫。它支持高并發(fā)度,成千上萬個用戶可同時操縱同一個數(shù)據(jù)庫。Berkeley DB能以足夠小的空間占用量運行于有嚴格約束的嵌入式系統(tǒng),也可以在高端服務器上耗用若干GB的內(nèi)存和若干TB的磁盤空間。
? ? Berkeley DB在嵌入式應用中比關系數(shù)據(jù)庫和面向?qū)ο髷?shù)據(jù)庫要好,有以下兩點原因:? ??
? ? (1)因為數(shù)據(jù)庫程序庫同應用程序在相同的地址空間中運行,所以數(shù)據(jù)庫操作不需要進程間的通訊。在一臺機器的不同進程間或在網(wǎng)絡中不同機器間進行進程通訊所花費的開銷,要遠遠大于函數(shù)調(diào)用的開銷;
? ? (2)因為Berkeley DB對所有操作都使用一組API接口,因此不需要對某種查詢語言進行解析,也不用生成執(zhí)行計劃,大大提高了運行效.
BerkeleyDB系統(tǒng)結(jié)構(gòu)
? ? Berkeley DB由五個主要的子系統(tǒng)構(gòu)成.包括: 存取管理子系統(tǒng)、內(nèi)存池管理子系統(tǒng)、事務子系統(tǒng)、鎖子系統(tǒng)以及日志子系統(tǒng)。其中存取管理子系統(tǒng)作為Berkeley DB數(shù)據(jù)庫進程包內(nèi)部核心組件,而其他子系統(tǒng)都存在于Berkeley DB數(shù)據(jù)庫進程包的外部。 ?
? ? 每個子系統(tǒng)支持不同的應用級別。
? ? 1.數(shù)據(jù)存取子系統(tǒng)
? ? 數(shù)據(jù)存取(Access Methods)子系統(tǒng)為創(chuàng)建和訪問數(shù)據(jù)庫文件提供了多種支持。Berkeley DB提供了以下四種文件存儲方法:
? ?哈希文件、B樹、定長記錄(隊列)和變長記錄(基于記錄號的簡單存儲方式),應用程序可以從中選擇最適合的文件組織結(jié)構(gòu)。
? ?程序員創(chuàng)建表時可以使用任意一種結(jié)構(gòu),并且可以在同一個應用程序中對不同存儲類型的文件進行混合操作。
? ? 在沒有事務管理的情況下,該子系統(tǒng)中的模塊可單獨使用,為應用程序提供快速高效的數(shù)據(jù)存取服務。
? ?數(shù)據(jù)存取子系統(tǒng)適用于不需事務只需快速格式文件訪問的應用。
? ? 2.內(nèi)存池管理子系統(tǒng)
? ? 內(nèi)存池(Memory pool)子系統(tǒng)對Berkeley DB所使用的共享緩沖區(qū)進行有效的管理。它允許同時訪問數(shù)據(jù)庫的多個進程或者進程的多個線程共享一個高速緩存,負責將修改后的頁寫回文件和為新調(diào)入的頁分配內(nèi)存空間。? ? 它也可以獨立于Berkeley DB系統(tǒng)之外,單獨被應用程序使用,為其自己的文件和頁分配內(nèi)存空間。內(nèi)存池管理子系統(tǒng)適用于需要靈活的、面向頁的、緩沖的共享文件訪問的應用。
? ? 3.事務子系統(tǒng)
? ? 事務(Transaction)子系統(tǒng)為Berkeley DB提供事務管理功能。它允許把一組對數(shù)據(jù)庫的修改看作一個原子單位,這組操作要么全做,要么全不做。在默認的情況下,系統(tǒng)將提供嚴格的ACID事務屬性,但是應用程序可以選擇不使用系統(tǒng)所作的隔離保證。該子系統(tǒng)使用兩段鎖技術和先寫日志策略來保證數(shù)據(jù)庫數(shù)據(jù)的正確性和一致性。? ? 它也可以被應用程序單獨使用來對其自身的數(shù)據(jù)更新進行事務保護。事務子系統(tǒng)適用于需要事務保證數(shù)據(jù)的修改的應用。
? ??
? ? 4.鎖子系統(tǒng)
? ? 鎖(Locking)子系統(tǒng)為Berkeley DB提供鎖機制,為系統(tǒng)提供多用戶讀取和單用戶修改同一對象的共享控制。數(shù)據(jù)存取子系統(tǒng)可利用該子系統(tǒng)獲得對頁或記錄的讀寫權限;事務子系統(tǒng)利用鎖機制來實現(xiàn)多個事務的并發(fā)控制。???該子系統(tǒng)也可被應用程序單獨采用。鎖子系統(tǒng)適用于一個靈活的、快速的、可設置的鎖管理器。
? ??
? ? 5.日志子系統(tǒng) ? ?
? ? 日志(Logging)子系統(tǒng)采用的是先寫日志的策略,用于支持事務子系統(tǒng)進行數(shù)據(jù)恢復,保證數(shù)據(jù)一致性。它不大可能被應用程序單獨使用,只能作為事務子系統(tǒng)的調(diào)用模塊。? ? 以上幾部分構(gòu)成了整個Berkeley DB數(shù)據(jù)庫系統(tǒng)。各部分的關系如下圖所示:
? ??
? ? 在這個模型中,應用程序直接調(diào)用的是數(shù)據(jù)存取子系統(tǒng)和事務管理子系統(tǒng),這兩個系統(tǒng)進而調(diào)用更下層的內(nèi)存管理子系統(tǒng)、鎖子系統(tǒng)和日志子系統(tǒng)。
? ??
? ? 由于幾個子系統(tǒng)相對比較獨立,所以應用程序在開始的時候可以指定哪些數(shù)據(jù)管理服務將被使用。可以全部使用,也可以只用其中的一部分。例如,如果一個應用程序需要支持多用戶并發(fā)操作,但不需要進行事務管理,那它就可以
只用鎖子系統(tǒng)而不用事務。有些應用程序可能需要快速的、單用戶、沒有事務管理功能的B樹存儲結(jié)構(gòu),那么應用程序可以使鎖子系統(tǒng)和事務子系統(tǒng)失效,這樣就會減少開銷。
BerkeleyDB存儲功能概述 ? ??
? ??
? ? Berkeley DB所管理數(shù)據(jù)的邏輯組織單位是若干個獨立或有一定關系的數(shù)據(jù)庫(database),每個數(shù)據(jù)庫由若干記錄組成,這些記錄全都被表示成(key,value)的形式.? ? 如果把一組相關的(key,value)對也看作一個表的話,那么每一個數(shù)據(jù)庫只允許存放一個table,這一點不同于一般的關系數(shù)據(jù)庫。實際上,在Berkeley DB中所提到的“數(shù)據(jù)庫”,相當于一般關系數(shù)據(jù)庫系統(tǒng)中的表;而“key/data”對相當于關系數(shù)據(jù)庫系統(tǒng)中的行(rows);Berkeley DB不提供關系數(shù)據(jù)庫中列直接訪問的功能,而是在“key/data”對中的data項中通過實際應用來封裝字段(列)。
? ? 在物理組織上,每一個數(shù)據(jù)庫在創(chuàng)建的時候可以由應用程序根據(jù)其數(shù)據(jù)特點來選擇一種合適的存儲結(jié)構(gòu)。可供選擇的四種文件存儲結(jié)構(gòu)分別是:哈希文件、B樹、定長記錄(隊列)和變長記錄(基于記錄號的簡單存儲方式)。
? ? 一個物理的文件中可以只存放一個單獨的數(shù)據(jù)庫,也可以存放若干相關或不相關的數(shù)據(jù)庫,而且這些數(shù)據(jù)庫可以分別采用除隊列之外任意不同的組織方式,以隊列組織的數(shù)據(jù)庫只能單獨存放于一個文件,不能同其他存儲類型混合存放。
? ? 一個文件除了受最大文件長度和存儲空間的約束之外,理論上可以存儲任意多個數(shù)據(jù)庫。因此系統(tǒng)定位一個數(shù)據(jù)庫通常需要兩個參數(shù)——“文件名”和“數(shù)據(jù)庫名”,這也是Berkeley DB不同于
一般關系數(shù)據(jù)庫的地方。
? ?Berkeley DB存儲系統(tǒng)為應用程序提供了一系列的接口函數(shù),用于對數(shù)據(jù)庫的管理和操作。其中包括:
? ? ? (1)數(shù)據(jù)庫的創(chuàng)建、打開、關閉、刪除、重命名等,以及對數(shù)據(jù)的檢索和增刪改操作;
? ? ? (2)提供一些附加的功能,例如讀取數(shù)據(jù)庫狀態(tài)信息、讀取所在文件的信息、讀取所在數(shù)據(jù)庫環(huán)境的信息、清空數(shù)據(jù)庫的內(nèi)容、數(shù)據(jù)庫的同步備份、版本升級、提示出錯信息等等;
? ? ? (3)系統(tǒng)還提供了游標機制,用于存取和訪問成組的數(shù)據(jù),以及對兩個或多個相關數(shù)據(jù)庫進行關聯(lián)和等值連接操作;
? ? ? (4)系統(tǒng)還給出了一些接口函數(shù)用于對存取策略進行優(yōu)化配置,比如應用程序可以自己設置B樹的排序比較函數(shù)、每頁中存放key的最少數(shù)目,哈希桶的填充因子、哈希函數(shù)、哈希表最大長度,隊列的最大長度,數(shù)據(jù)庫存放的字節(jié)順序,
底層存儲頁的大小,內(nèi)存分配函數(shù),高速緩存的大小,定長記錄的大小和填充位,變長記錄所用的分隔符等等。
二、Berkeley DB的應用?
1、從官方網(wǎng)站http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/overview/index.html下載Berkeley DB的安裝文件及JAVA開發(fā)包。?
2、在windows安裝Berkeley DB,一直按下一步即可。為開發(fā)方便,安裝了windows版本,正式運行時應該使用Linux版本。(設置path時出錯,需要以管理員身份運行安裝程序)。?
3、將JAVA開發(fā)包中的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)打開數(shù)據(jù)庫
(2)向數(shù)據(jù)庫寫入數(shù)據(jù)
(3)根據(jù)Key值讀取某個數(shù)據(jù)
(4)讀取全量數(shù)據(jù)列表
(5)根據(jù)Key值刪除某個數(shù)據(jù)
(6)關閉數(shù)據(jù)庫
注意:由于各個操作可能對應同一個數(shù)據(jù)庫,因此是否需要使用單例模式?
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 {// 數(shù)據(jù)庫環(huán)境private Environment env = null;// 數(shù)據(jù)庫private static Database frontierDatabase = null;// 數(shù)據(jù)庫名private static String dbName = "frontier_database";public BerkeleyDBUtil(String homeDirectory) {// 1、創(chuàng)建EnvironmentConfigEnvironmentConfig envConfig = new EnvironmentConfig();envConfig.setTransactional(true);envConfig.setAllowCreate(true);// 2、使用EnvironmentConfig配置Environmentenv = new Environment(new File(homeDirectory), envConfig);// 3、創(chuàng)建DatabaseConfigDatabaseConfig dbConfig = new DatabaseConfig();dbConfig.setTransactional(true);dbConfig.setAllowCreate(true);// 4、使用Environment與DatabaseConfig打開DatabasefrontierDatabase = env.openDatabase(null, dbName, dbConfig);}/** 向數(shù)據(jù)庫中寫入記錄,并判斷是否可以有重復數(shù)據(jù)。 傳入key和value* 若可以有重復數(shù)據(jù),則直接使用put()即可,若不能有重復數(shù)據(jù),則使用putNoOverwrite()。*/public boolean writeToDatabase(String key, String value, boolean isOverwrite) {try {// 設置key/value,注意DatabaseEntry內(nèi)使用的是bytes數(shù)組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、寫入數(shù)據(jù)if (isOverwrite) {status = frontierDatabase.put(txn, theKey, theData);} else {status = frontierDatabase.putNoOverwrite(txn, theKey,theData);}txn.commit();if (status == OperationStatus.SUCCESS) {System.out.println("向數(shù)據(jù)庫" + dbName + "中寫入:" + key + ","+ value);return true;} else if (status == OperationStatus.KEYEXIST) {System.out.println("向數(shù)據(jù)庫" + dbName + "中寫入:" + key + ","+ value + "失敗,該值已經(jīng)存在");return false;} else {System.out.println("向數(shù)據(jù)庫" + dbName + "中寫入:" + key + ","+ value + "失敗");return false;}} catch (LockConflictException lockConflict) {txn.abort();System.out.println("向數(shù)據(jù)庫" + dbName + "中寫入:" + key + "," + value+ "出現(xiàn)lock異常");return false;}} catch (Exception e) {// 錯誤處理System.out.println("向數(shù)據(jù)庫" + dbName + "中寫入:" + key + "," + value+ "出現(xiàn)錯誤");return false;}}/** 從數(shù)據(jù)庫中讀出數(shù)據(jù) 傳入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、讀取數(shù)據(jù)OperationStatus status = frontierDatabase.get(txn, theKey,theData, LockMode.DEFAULT);txn.commit();if (status == OperationStatus.SUCCESS) {// 3、將字節(jié)轉(zhuǎn)換成Stringbyte[] retData = theData.getData();String value = new String(retData, "UTF-8");System.out.println("從數(shù)據(jù)庫" + dbName + "中讀取:" + key + ","+ value);return value;} else {System.out.println("No record found for key '" + key + "'.");return "";}} catch (LockConflictException lockConflict) {txn.abort();System.out.println("從數(shù)據(jù)庫" + dbName + "中讀取:" + key + "出現(xiàn)lock異常");return "";}} catch (UnsupportedEncodingException e) {e.printStackTrace();return "";}}/** 遍歷數(shù)據(jù)庫中的所有記錄,返回list*/public ArrayList<String> getEveryItem() {// TODO Auto-generated method stubSystem.out.println("===========遍歷數(shù)據(jù)庫" + dbName + "中的所有數(shù)據(jù)==========");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方法來遍歷游標獲取數(shù)據(jù)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處理出現(xiàn)異常");txn.abort();if (myCursor != null) {myCursor.close();}return null;}}/** 根據(jù)key值刪除數(shù)據(jù)庫中的一條記錄*/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方法來遍歷游標獲取數(shù)據(jù)TransactionConfig txConfig = new TransactionConfig();txConfig.setSerializableIsolation(true);txn = env.beginTransaction(null, txConfig);DatabaseEntry theKey;theKey = new DatabaseEntry(key.getBytes("UTF-8"));//2、刪除數(shù)據(jù) 并提交OperationStatus res = frontierDatabase.delete(txn, theKey);txn.commit();if (res == OperationStatus.SUCCESS) {System.out.println("從數(shù)據(jù)庫" + dbName + "中刪除:" + key);success = true;return success;} else if (res == OperationStatus.KEYEMPTY) {System.out.println("沒有從數(shù)據(jù)庫" + dbName + "中找到:" + key + "。無法刪除");} else {System.out.println("刪除操作失敗,由于" + res.toString());}return false;} catch (UnsupportedEncodingException e) {e.printStackTrace();return false;} catch (LockConflictException lockConflict) {System.out.println("刪除操作失敗,出現(xiàn)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();}}}轉(zhuǎn)載于:https://www.cnblogs.com/eaglegeek/p/4557923.html
總結(jié)
以上是生活随笔為你收集整理的Berkeley DB基础教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QObject 的拷贝构造和赋值操作
- 下一篇: 导航栏动画的效果