一、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;
	@Before
	public void setup() {
		dbUtil = new BerkeleyDBUtil("D:/tmp");
	@Test
	public void testWriteToDatabase() {
		for (int i = 0; i < 10; i++){
		dbUtil.writeToDatabase(i+"", "学生"+i, true);
	@Test
	public void testReadFromDatabase() {
		String value = dbUtil.readFromDatabase("2");
		assertEquals(value, "学生2");
	@Test
	public void testGetEveryItem() {
		int size = dbUtil.getEveryItem().size();
		assertEquals(size, 10);
	@Test
	public void testDeleteFromDatabase() {
		dbUtil.deleteFromDatabase("4");
		assertEquals(9, dbUtil.getEveryItem().size());
	public void cleanup() {
		dbUtil.closeDB();
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、创建EnvironmentConfig
		EnvironmentConfig envConfig = new EnvironmentConfig();
		envConfig.setTransactional(true);
		envConfig.setAllowCreate(true);
		// 2、使用EnvironmentConfig配置Environment
		env = new Environment(new File(homeDirectory), envConfig);
		// 3、创建DatabaseConfig
		DatabaseConfig dbConfig = new DatabaseConfig();
		dbConfig.setTransactional(true);
		dbConfig.setAllowCreate(true);
		// 4、使用Environment与DatabaseConfig打开Database
		frontierDatabase = 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、将字节转换成String
					byte[] 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 stub
		System.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原因:
    DB最初开发的目的是以新的HASH访问算法来代替旧的hsearch函数和大量的dbm实现(如AT&T的dbm,Berkeley的ndbm,GNU项目的gdbm),DB的第一个发行版在1991年出现,当时还包含了B+树数据访问算法。在1992年,BSD UNIX第4.4发行版中包含了DB1.85版。基本上认为这是DB的第一个正式版。在1996年中期,...
                                       一、内存数据库:FastDBBerkeleyDB、SQLite   内存数据库, 顾名思义就是将数据放在内存中直接操作的数据库。相对于磁盘,内存的数据读写速度要高出几个数量级,将数据保存在内存中相比从磁盘上访问能够极大地提高应用的性能。 最近要做一个项目,需要用到实时数据库,PI太贵了,想找一个免费的,实在不行就只能自己编了。找了半天,找到了FastDBBerkeleyDB和SQLite...
                                    像mysql 这类基于c/s结构的关系型数据库系统虽然代表着目前数据库应用的主流,但却并不能满足所有应用场合的需要。有时我们需要的可能只是一个简单的基于磁盘文件的数据库系统。这样不仅可以避免安装庞大的数据库服务器,而且还可以简化数据库应用程序的设计。berkeley db正是基于这样的思想提出来的。[编辑本段]berkeley db简介berkeley db是一个开放源代码的内嵌式数据库管理系统,...
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万
定义:Berkeley DB是一个开源的文件数据库,介于关系数据库与内存数据库之间,使用方式与内存数据库类似,它提供的是一系列直接访问数据库的函数,而不是像关系数据库那样需要网络通讯、SQL解析等步骤。
1)开源的kv类型数据库
2)文件数据库:
优点:数据保存在单一文件中,部署以及发布简单,使用内嵌在应用程序中。
缺点:数据库打开时,文件会被加载到内存,因为数据库不宜过大。
3)嵌入式...
                                    1、用来存储类信息的数据库不要求能够存储重复的关键字 例: dbConfig.setSortedDuplicates(false);2、DatabaseEntrt能够支持任何能够转化为bytes数组形式的基本数据。包括java基本类型和可序列化的对象(getBytes转换为UTF-8编码,可以不转) 例: DatabaseEntry theKey = new Da...
Berkeley DB 概述
皮东Berkeley DB官方网站:http://www.sleepycat.com/ Berkeley DB是由美国Sleepycat Software公司开发的一套开放源码的嵌入式数据库的程序库(database library),它为应用程序提供可伸缩的、高性能的、有事务保护功能的数据管理服务。Berkeley DB为数据的存取和管理提供了一组简洁的函...
                                    Berkeley DB 是一个嵌入式数据库,它适合于管理海量的(256T)、简单的数据。BDB是以键值对(value/key)来存储和管理数据库的。键可以重复,数据值可以是任意类型的。BDB的底层是用B+树或者其他算法实现的。我用的jar包是B+树实现的版本。
Berkeley DB是用Environment对象来管理数据库,一个Environment可以管理多个database。每个datab
                                    Berkeley DB的使用
最近碰到一个项目需要多进程读写一份共享数据,并且共享数据的几个字段需要有倒排索引方便查询,想利用现有数据库快速建立一个原型,于是调研了一下流行的一些nosql数据库。发觉Berkeley DB虽然是一个既古老又流行的开源数据库,但是关于BDB使用的文章却很少,甚至公司DBA对BDB的特性都不太了解……于是花了好几天读了一遍BDB的references和c
超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
候选键:是最小超键,即没有冗余元素的超键。
主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)...
                                    Berkeley DB的数据存储结构
BDB支持四种数据存储结构及相应算法,官方称为访问方法(Access Method),分别是哈希表(Hash Table)、B树(BTree)、队列(Queue)、记录号(Recno)。在创建数据库的时候,必须通过dbtype参数将存储结构指定为上述结构中的一种,一旦数据库文件已创建则不能再更改其结构。
BTree...
                                    示例文档:https://docs.oracle.com/cd/E17277_02/html/TransactionGettingStarted/index.html
API:https://docs.oracle.com/cd/E17277_02/html/java/index.html?com/sleepycat/je/package-summary.html
Oracle Berkeley ...