如果你有海量的数据,这些数据相对比较简单,且没有复杂的关系,关键的是你不想用像MySQL和SQLServer那样的数据库,你只想在程序中处理这些数据,那么,Berkeley DB也许是一个非常好的选择!
Berkeley DB(BDB)是一个高效的嵌入式数据库编程库,C语言、C++、Java、Perl、Python、Tcl以及其他很多语言都有其对应的API。Berkeley DB可以保存任意类型的键/值对(Key/Value Pair),而且可以为一个键保存多个数据。Berkeley DB支持让数千的并发线程同时操作数据库,支持最大256TB的数据,广泛用于各种操作系统,其中包括大多数类Unix操作系统、Windows操作系统以及实时操作系统。
JE官网:http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/overview/index.html
1. 大型数据库的支持:它支持从1到数百万级的数据量,数据库的大小限制基本上受限于你的硬件支持。
2. 多线程,多进程支持:JE读写操作都可以是多线程,使用记录级锁定为线程应用程序提供高并发性。此外,JE使用死锁超时检测的机制来确保不会有两个线程无限期的死锁。JE允许多个进程访问同一个DB,但在这种情况下, Berkeley 只允许一个线程进行写操作,读操作随意。
3. 事务:原子性,可恢复,隔离性。
4. 内存Cache:为了减少IO操作提高性能,将数据暂存在内存里面。
5. 索引。
Database.putNoDupData():向数据库写入数据(该方法仅用于支持重复key的数据库),如果key和value对应的记录已经存在,那么操作结果是:OperationStatus.KEYEXIST
Database.get() :检索key对应的记录,如果没有找到,操作结果返回:OperationStatus.NOTFOUND
Database.getSearchBoth() :根据key和value 检索数据库记录,如果没有找到,操作结果返回:OperationStatus.NOTFOUND
package berkeley.demo;
import java.io.File;
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.LockMode;
import com.sleepycat.je.OperationStatus;
public class SimpleDemo {
/**
* @param envHomePath
*/
public static void testSimpleData(String envHomePath, String databaseName) {
Environment mydbEnv = null;
Database myDatabase = null;
System.out.println(" ---- > EnvironmentConfig init");
// 创建一个EnvironmentConfig配置对象
EnvironmentConfig envCfg = new EnvironmentConfig();
// 如果设置了true则表示当数据库环境不存在时候重新创建一个数据库环境,默认为false.
envCfg.setAllowCreate(true);
// 设置数据库缓存大小
envCfg.setCacheSize(1024 * 1024 * 20);
// 事务支持,如果为true,则表示当前环境支持事务处理,默认为false,不支持事务处理。
envCfg.setTransactional(true);
try {
System.out.println(" ---- > Environment init");
mydbEnv = new Environment(new File(envHomePath), envCfg);
System.out.println(" ---- > DatabaseConfig init");
DatabaseConfig dbCfg = new DatabaseConfig();
// 如果数据库不存在则创建一个
dbCfg.setAllowCreate(true);
// 如果设置为true,则支持事务处理,默认是false,不支持事务
dbCfg.setTransactional(true);
System.out.println(" ---- > open Database: " + databaseName);
myDatabase = mydbEnv.openDatabase(null, databaseName, dbCfg);
System.out.println(" ---- > test CRUD ");
//生成键/值,并put存入
String key = "myfirstdata";
String value = "Hello Berkeley";
DatabaseEntry keyEntry = new DatabaseEntry(key.getBytes("utf-8"));
DatabaseEntry valEntry = new DatabaseEntry(value.getBytes("utf-8"));
System.out.println(" ---- > put data with key :" + key);
OperationStatus status = myDatabase.put(null, keyEntry, valEntry);
System.out.println(" ---- > put status: " + status);
//查询
System.out.println(" ---- > get key :" + key);
DatabaseEntry valEntry4Get = new DatabaseEntry();
status = myDatabase.get(null, keyEntry, valEntry4Get,
LockMode.DEFAULT);
if (status == OperationStatus.SUCCESS) {
value = new String(valEntry4Get.getData(), "utf-8");
System.out.println(" ---- > get key success value:" + value);
} else {
System.out.println(" ---- > get key failed.");
}
//更新
System.out.println(" ---- > update data with key :" + key);
value = "Hello Google";
status = myDatabase.put(null, keyEntry,
new DatabaseEntry(value.getBytes("utf-8")));
System.out.println(" ---- > update status: " + status);
System.out.println(" ---- > after update get key :" + key);
status = myDatabase.get(null, keyEntry, valEntry4Get,
LockMode.DEFAULT);
if (status == OperationStatus.SUCCESS) {
value = new String(valEntry4Get.getData(), "utf-8");
System.out.println(" ---- > get success key value:" + value);
} else {
System.out.println(" ---- > get key value failed.");
}
//删除
System.out.println(" ---- > delete key :" + key);
status = myDatabase.delete(null, keyEntry);
System.out.println(" ---- > delete status: " + status);
System.out.println(" ---- > after delete get key :" + key);
status = myDatabase.get(null, keyEntry, valEntry4Get,
LockMode.DEFAULT);
if (status == OperationStatus.SUCCESS) {
value = new String(valEntry4Get.getData(), "utf-8");
System.out.println(" ---- > get success key value:" + value);
} else {
System.out.println(" ---- > get key value failed.");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != myDatabase) {
myDatabase.close();
}
if (null != mydbEnv) {
// 在关闭环境前清理下日志
mydbEnv.cleanLog();
mydbEnv.close();
mydbEnv = null;
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(" ==== > Demo Test Start < ====");
String envHomePath = "D:/test";
String databaseName = "first-db";
SimpleDemo.testSimpleData(envHomePath, databaseName);
System.out.println(" ==== > Demo Test End < ====");
}
}
public class WebURLTupleBinding extends TupleBinding {
@Override
public WebURL entryToObject(TupleInput input) {
WebURL webURL = new WebURL();
webURL.setURL(input.readString());
webURL.setDocid(input.readInt());
webURL.setParentDocid(input.readInt());
webURL.setParentUrl(input.readString());
webURL.setDepth(input.readShort());
webURL.setPriority(input.readByte());
webURL.setAnchor(input.readString());
webURL.setElement(input.readString());
return webURL;
}
@Override
public void objectToEntry(WebURL url, TupleOutput output) {
output.writeString(url.getURL());
output.writeInt(url.getDocid());
output.writeInt(url.getParentDocid());
output.writeString(url.getParentUrl());
output.writeShort(url.getDepth());
output.writeByte(url.getPriority());
output.writeString(url.getAnchor());
output.writeString(url.getElement());
}
}
用自定义类TupleBinding转化后即可存入DB:
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
Database urlsDB = env.openDatabase(null, dbName, dbConfig);
WebURLTupleBinding webURLBinding = new WebURLTupleBinding();
DatabaseEntry value = new DatabaseEntry();
WebURL url = new WebURL();
webURLBinding.objectToEntry(url, value);
urlsDB.put(txn, getDatabaseEntryKey(url), value);
JAVA开源爬虫crawler4j就是使用JE进行URL存储的,测过数据量在百万以下都是非常快的,百万以上也还可以接受,千万就不知道了,个人觉得到百万以上还是用非嵌入式数据库好一些!
参考文档: Oracle 白皮书:Berkeley DB Java版 直接持久层基础