Berkely DB对于高并发、要求速度快的应用来说是个不错的选择,mysql就是用BDB实现的(mysql的后台) ,mysql快,BDB比mysql还要快N倍。BDB是一种嵌入式的、非关系数据库,它与其他的关系数据库RMDBS不同,它没有提供SQL,而是提供 了自己的访问接口。作为一种嵌入式的数据库,它是进程内模式的,也就是说它和应用程序在同一内存空间运行,所以速度要高很多,与嵌入式的数据库如 Derby、HSQLDB(都是RMDBS的)相比,它效率更高,使用方法也有很大的不同。现在BDB以被Oracle收购。Berkely DB提供的文档Getting Started with Berkeley DB Java Edition可以说是短小精悍(113页),入门相当不错。下面Get Start吧:
Environment:

首先要接触的就是Environment了,使用它来open database以及做一管理方面的事情.

创建Environment,还需要Environment的一些配置信息EnvironmentConfig。

下面是创建的过程:

  1. EnvironmentConfig envConfig = new EnvironmentConfig();
  2. envConfig.setAllowCreate(true);
  3. myDbEnvironment = new Environment(new File("/export/dbEnv"),
  4. envConfig);

其中EnvironmentConfig提供了许多配置参数,常用的有:

envConfig.setAllowCreate()//如果不存在的env的话,是否要创建一个新的

envConfig.setReadOnly()//是否为只读的

envConfig.setTransactional()//是否使用事务

参数都是boolean类型的

除了EnvironmentConfig外,还有EnvironmentMutableConfig,他实际是EnvironmentConfig的父类,使用他来配置在创建完Environment之后可以改变

的属性:

setCachePercent()//设置cache的大小占JVM memory的百分比

setCacheSize()//设置cache的大小

setTxnNoSync()//事务提交是否将改变的记录写入磁盘

setTxnWriteNoSync()//事务提交是否将log写入磁盘

下面看一下使用EnvironmentMutableConfig的方法:

  1. Environment myEnv = new Environment(new File("/export/dbEnv"), null);
  2. EnvironmentMutableConfig envMutableConfig =
  3. new EnvironmentMutableConfig();
  4. envMutableConfig.setTxnNoSync(true);
  5. myEnv.setMutableConfig(envMutableConfig);

Environment通过close来关闭,释放资源

下面看看Environment在管理方面的一些方法:

可以通过Environment获得EnvironmentStats,他提供了Environment一些状态信息,

例如使用

  1. long cacheMisses = myEnv.getStats(null).getNCacheMiss();

我们可以获得cache未命中的次数,据此来调整cache的大小

可以同过Environment.getDatabaseNames()来获得Environment的数据库的名字:

  1. List myDbNames = myDbEnv.getDatabaseNames();
  2. for(int i=0; i < myDbNames.size(); i++) {
  3. System.out.println("Database Name: " + (String)myDbNames.get(i));
  4. }

可以通过Environment.removeDatabase()来删除一个数据库:

  1. String dbName = myDB.getDatabaseName();
  2. myDB.close();
  3. myDBEnv.removeDatabase(null,dbName);

可以使用Environment.renameDatabase()来重新命名一个数据库:

  1. String dbName = myDB.getDatabaseName();
  2. String dbNewName = new String(dbName + ".new", "UTF-8");
  3. myDB.close();
  4. myDBEnv.renameDatabase(null,dbName,dbNewName);

可以使用Environment.truncateDatabase()来删除数据库中的所有记录:

  1. myEnv.truncate(null, // txn handle
  2. myDatabase.getDatabaseName(), // database name
  3. true//whether to return the count of deleted records
  4. );

第三个参数是否返回删除的记录数,性能有很大不同。false的话会很快

Database:

最重要的一些操作大多都在Database里了,和Environment一样,它也有许多

配置的选项DatabaseConfig,我们先看看选项:

DatabaseConfig.setAllowCreate()//不能存在的话是open操作否创建新的

DatabaseConfig.setBtreeComparator()//设置Btree的比较器

DatabaseConfig.setDuplicateComparator()//设置判断重复的比较器

DatabaseConfig.setSortedDuplicates()//是否允许重复的记录

DatabaseConfig.setExclusiveCreate()//设为true,如果当前数据库已存在,则open失败,也就是说open操作会导致一个新的数据库被创建,默认为false

DatabaseConfig.setReadOnly()//是否是只读的

DatabaseConfig.setTransactional()//是否使用事务

下面我们看看Database的使用流程:

  1. EnvironmentConfig envConfig = new EnvironmentConfig();
  2. envConfig.setAllowCreate(true);
  3. myDbEnvironment = new Environment(new File("/export/dbEnv"), envConfig);
  4. DatabaseConfig dbConfig = new DatabaseConfig();
  5. dbConfig.setAllowCreate(true);
  6. myDatabase = myDbEnvironment.openDatabase(null,
  7. "sampleDatabase",
  8. dbConfig);

我们通过Environment的openDatabase来创建Database对象。使用完了Database使用

close方法来关闭数据库释放资源。

Database Records

Database Record是保存在数据库的内容,包含Key和value两部分,他们都被封装成

DatabaseEntry,DatabaseEntry只能存放字节数组,所以只要能把Key和Value是什么

类型的,只要能转化成字节数组就可以被DatabaseEntry封装。基本类型JE都有对应的Binding,复杂的类型可以使用序列化和自定义binding来实现。

下那面我们看看一个使用方法:

  1. String aKey = "key";
  2. String aData = "data";
  3. try {
  4. DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
  5. DatabaseEntry theData = new DatabaseEntry(aData.getBytes("UTF-8"));
  6. } catch (Exception e) {
  7. }

我们不应该依赖机器默认的编码,通常要指定特定的编码方法getBytes("UTF-8");

我们先看看怎么从数据库中读写记录:

通过Database.put()和Database.get()我们可以从数据库中读写记录

put:

  1. String aKey = "myFirstKey";
  2. String aData = "myFirstData";
  3. try {
  4. DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
  5. DatabaseEntry theData = new DatabaseEntry(aData.getBytes("UTF-8"));
  6. myDatabase.put(null, theKey, theData);
  7. } catch (Exception e) {
  8. }

get:

  1. String aKey = "myFirstKey";
  2. try {
  3. DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
  4. DatabaseEntry theData = new DatabaseEntry();
  5. if (myDatabase.get(null, theKey, theData, LockMode.DEFAULT) ==
  6. OperationStatus.SUCCESS) {
  7. byte[] retData = theData.getData();
  8. String foundData = new String(retData, "UTF-8");
  9. System.out.println("For key: '" + aKey + "' found data: '" +
  10. foundData + "'.");
  11. } else {
  12. System.out.println("No record found for key '" + aKey + "'.");
  13. }
  14. } catch (Exception e) {
  15. }

删除操作:

  1. String aKey = "myFirstKey";
  2. DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
  3. myDatabase.delete(null, theKey);

使用BIND APIs来操作基本类型:

我们可以使用JE提供的Bind Apis来操作数字类型和字符串类型:

以Long为例:

存储数据使用Bind Apis一般步骤如下:

1、通过EntryBinding binding =TupleBinding.getPrimitiveBinding(Long.class);

2、通过EntryBinding 把数据放到DatabaseEntry中:

myBinding.objectToEntry(data, dataEntry);

获取数据使用Bind Apis一般步骤如下:

1、通过EntryBinding binding =TupleBinding.getPrimitiveBinding(Long.class);

2、通过EntryBinding将Entry转换成Object Long theLong = (Long) myBinding.entryToObject(theData);

下面代码以测试的形式演示了整个过程:

  1. package edu.jlu.fuliang;
  2. import java.io.File;
  3. import com.sleepycat.bind.EntryBinding;
  4. import com.sleepycat.bind.tuple.TupleBinding;
  5. import com.sleepycat.je.Database;
  6. import com.sleepycat.je.DatabaseConfig;
  7. import com.sleepycat.je.DatabaseEntry;
  8. import com.sleepycat.je.Environment;
  9. import com.sleepycat.je.EnvironmentConfig;
  10. import com.sleepycat.je.LockMode;
  11. import junit.framework.TestCase;
  12. public class PrimitiveBindingTest extends TestCase{
  13. private Environment env;
  14. private Database db;
  15. private String key = "akey";
  16. private Long data = 1234556633L;
  17. public void setUp()throws Exception{
  18. EnvironmentConfig envConfig = new EnvironmentConfig();
  19. envConfig.setAllowCreate(true);
  20. env = new Environment(new File("etc/dbEnv"),envConfig);
  21. DatabaseConfig dbConfig = new DatabaseConfig();
  22. dbConfig.setAllowCreate(true);
  23. db = env.openDatabase(null, "myDB", dbConfig);
  24. DatabaseEntry keyEntry = new DatabaseEntry(key.getBytes("UTF-8"));
  25. DatabaseEntry dataEntry = new DatabaseEntry();
  26. EntryBinding myBinding = TupleBinding.getPrimitiveBinding(Long.class);
  27. myBinding.objectToEntry(data, dataEntry);
  28. db.put(null, keyEntry, dataEntry);
  29. }
  30. public void testGet()throws Exception{
  31. DatabaseEntry keyEntry = new DatabaseEntry(key.getBytes("UTF-8"));
  32. DatabaseEntry dataEntry = new DatabaseEntry();
  33. EntryBinding binding = TupleBinding.getPrimitiveBinding(Long.class);
  34. db.get(null, keyEntry, dataEntry, LockMode.DEFAULT);
  35. Long l = (Long)binding.entryToObject(dataEntry);
  36. assertEquals(l,data);
  37. }
  38. public void tearDown()throws Exception{
  39. db.close();
  40. env.truncateDatabase(null, "myDB",false);
  41. env.close();
  42. }
  43. }

序列化复杂的类型

步骤如下:

1、要存储的对象的类需要实现java.io.Serializable

2、打开两个数据库,一个存放数据,另一个存放类的信息

3、实例化com.sleepycat.bind.serial.StoredClassCatalog对象

4、创建uses com.sleepycat.bind.serial.SerialBinding对象

5、使用SerialBinding把对象放到DatabaseEntry中

下面是使用一个能够完整描述这个过程的例子来说明这个过程:

  1. package edu.jlu.fuliang;
  2. import java.io.File;
  3. import com.sleepycat.bind.EntryBinding;
  4. import com.sleepycat.bind.serial.SerialBinding;
  5. import com.sleepycat.bind.serial.StoredClassCatalog;
  6. import com.sleepycat.je.Database;
  7. import com.sleepycat.je.DatabaseConfig;
  8. import com.sleepycat.je.DatabaseEntry;
  9. import com.sleepycat.je.DatabaseException;
  10. import com.sleepycat.je.Environment;
  11. import com.sleepycat.je.EnvironmentConfig;
  12. import com.sleepycat.je.LockMode;
  13. import junit.framework.TestCase;
  14. public class SerializableTypeTest extends TestCase{
  15. private Person person;
  16. private Environment env;
  17. private Database db,classDB;
  18. private StoredClassCatalog classCatalog;
  19. public void setUp()throws Exception{
  20. person = new Person();
  21. person.setAge(12);
  22. person.setName("zhansan");
  23. person.setSex('m');
  24. EnvironmentConfig envConfig = new EnvironmentConfig();
  25. envConfig.setAllowCreate(true);
  26. env = new Environment(new File("etc/dbEnv"),envConfig);
  27. DatabaseConfig dbConfig = new DatabaseConfig();
  28. dbConfig.setAllowCreate(true);
  29. db = env.openDatabase(null, "myDB", dbConfig);
  30. classDB = env.openDatabase(null, "classDB", dbConfig);
  31. classCatalog = new StoredClassCatalog(classDB);
  32. EntryBinding dataBinding = new SerialBinding(classCatalog,Person.class);
  33. DatabaseEntry keyEntry = new DatabaseEntry(person.getName().getBytes("UTF-8"));
  34. DatabaseEntry dataEntry = new DatabaseEntry();
  35. dataBinding.objectToEntry(person, dataEntry);
  36. db.put(null, keyEntry, dataEntry);
  37. }
  38. public void testGet()throws Exception{
  39. EntryBinding dataBinding = new SerialBinding(classCatalog,Person.class);
  40. DatabaseEntry keyEntry = new DatabaseEntry(person.getName().getBytes("UTF-8"));
  41. DatabaseEntry dataEntry = new DatabaseEntry();
  42. db.get(null, keyEntry, dataEntry, LockMode.DEFAULT);
  43. Person p = (Person)dataBinding.entryToObject(dataEntry);
  44. assertEquals(p.getName(),person.getName());
  45. assertEquals(p.getAge(),person.getAge());
  46. assertEquals(p.getSex(), person.getSex());
  47. }
  48. public void tearDown()throws Exception{
  49. db.close();
  50. classDB.close();
  51. env.truncateDatabase(null, "myDB", false);
  52. env.truncateDatabase(null, "classDB", false);
  53. env.close();
  54. }
  55. }

要存储的对象对应的类

  1. package edu.jlu.fuliang;
  2. import java.io.Serializable;
  3. public class Person implements Serializable{
  4. private String name;
  5. private int age;
  6. private char sex;
  7. public int getAge() {
  8. return age;
  9. }
  10. public void setAge(int age) {
  11. this.age = age;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public char getSex() {
  20. return sex;
  21. }
  22. public void setSex(char sex) {
  23. this.sex = sex;
  24. }
  25. }

自定义元组绑定:

存储复杂对象自定义元组绑定的步骤:

1、创建要存储的对象,这个对象的类没有必要实现Serializable接口:

2、扩展com.sleepycat.bind.tuple.TupleBinding来实现自定义的Binging

3、创建2步欻关键的自定义binding对象

4、将创建的对象是用自定义个binding放到DatabaseEntry中

5、使用put方法存入数据库

下面的例子说明了这个过程:

自定义Binging:

  1. package edu.jlu.fuliang;
  2. import com.sleepycat.bind.tuple.TupleBinding;
  3. import com.sleepycat.bind.tuple.TupleInput;
  4. import com.sleepycat.bind.tuple.TupleOutput;
  5. public class PersonTupleBinding extends TupleBinding{
  6. @Override
  7. public Object entryToObject(TupleInput ti) {
  8. Person person = new Person();
  9. person.setName(ti.readString());
  10. person.setAge(ti.readInt());
  11. person.setSex(ti.readChar());
  12. return person;
  13. }
  14. @Override
  15. public void objectToEntry(Object obj, TupleOutput output) {
  16. Person person = (Person)obj;
  17. output.writeString(person.getName());
  18. output.writeInt(person.getAge());
  19. output.writeChar(person.getSex());
  20. }
  21. }

put/get的使用过程:

    1. package edu.jlu.fuliang;
    2. import java.io.File;
    3. import com.sleepycat.je.Database;
    4. import com.sleepycat.je.DatabaseConfig;
    5. import com.sleepycat.je.DatabaseEntry;
    6. import com.sleepycat.je.DatabaseException;
    7. import com.sleepycat.je.Environment;
    8. import com.sleepycat.je.EnvironmentConfig;
    9. import com.sleepycat.je.LockMode;
    10. import junit.framework.TestCase;
    11. public class CustomTupleBindingTest extends TestCase{
    12. private Person person;
    13. private Environment env;
    14. private Database db;
    15. public void setUp()throws Exception{
    16. person = new Person();
    17. person.setAge(12);
    18. person.setName("zhansan");
    19. person.setSex('m');
    20. EnvironmentConfig envConfig = new EnvironmentConfig();
    21. envConfig.setAllowCreate(true);
    22. env = new Environment(new File("etc/dbEnv"),envConfig);
    23. DatabaseConfig dbConfig = new DatabaseConfig();
    24. dbConfig.setAllowCreate(true);
    25. db = env.openDatabase(null, "myDB", dbConfig);
    26. PersonTupleBinding binding = new PersonTupleBinding();
    27. DatabaseEntry keyEntry = new DatabaseEntry(person.getName().getBytes("UTF-8"));
    28. DatabaseEntry dataEntry = new DatabaseEntry();
    29. binding.objectToEntry(person, dataEntry);
    30. db.put(null, keyEntry, dataEntry);
    31. }
    32. public void testGet()throws Exception{
    33. PersonTupleBinding binding = new PersonTupleBinding();
    34. DatabaseEntry keyEntry = new DatabaseEntry(person.getName().getBytes("UTF-8"));
    35. DatabaseEntry dataEntry = new DatabaseEntry();
    36. db.get(null, keyEntry, dataEntry, LockMode.DEFAULT);
    37. Person p = (Person)binding.entryToObject(dataEntry);
    38. assertEquals(p.getName(),person.getName());
    39. assertEquals(p.getAge(),person.getAge());
    40. assertEquals(p.getSex(), person.getSex());
    41. }
    42. public void tearDown()throws Exception{
    43. db.close();
    44. env.truncateDatabase(null, "myDB", false);
    45. env.close();
    46. }
    47. }
05-16 19:00