BerkeleyDB-JE 使用BaseAPI(七)
本篇开始介绍二级数据库(Secondary Databases)的使用。
通常情况下,我们根据key值来查找JE中的记录,但是key值不一定会包含你所要想要查询的值,比如JE中有个用户库,你使用一个唯一的没有什么意义的ID作为key值,而data值是一个复杂的java对象,它封装了用户名,性别,生日,年龄等信息,如果你想查找某个具有某个名字的用户记录,那么你可能要遍历整个数据库。这时候JE还提供了一个选择,就是使用Secondary Databases。
在这里Secondary Databases可以使你创建一个基于用户名的索引,这样你就可以使用这个索引进行查询。在JE中,包含了你想要的数据的数据库叫做主数据库(Primary Database),而包含了可选的key集合的用于访问Primary database中数据的数据库称为二级数据库(Secondary Databases)。
一旦你打开了一个Secondary Databases,JE会为你管理其中的数据。当你添加或者删除Primary Database中记录的时候,JE会自动对Secondary Databases中的数据作出必要的修改;当你修改了Primary Database中的记录,并且这个修改会导致Secondary Databases中的key发生变化的时候,JE也会调整Secondary Databases。
一定要注意一点,你不能直接对Secondary Databases中的数据进行操作,虽然其中存在这样的API,但是如果你调用了这些API,则会报出异常。唯一的例外是你可以删除Secondary Databases中的数据。
当你从Secondary Databases中获取记录值的时候,实际上返回的是对应在Primary Database中的记录。
下面开始讲解如何打开和关闭Secondary Databases,有5个步骤:
1.打开Primary Database
2.实例化SecondaryKeyCreator对象
3.实例化SecondaryConfig对象
4.为SecondaryConfig设置SecondaryKeyCreator对象
5.用Primary Database和SecondaryConfig打开Secondary Databases
相比打开普通的Database,要打开Secondary Database,这里最大的区别就在于多了个SecondaryKeyCreator对象。这个对象是用来创建你想要的索引的。你能使用任何数据来创建key,一般情况下,你会使用Primary Database中的data值来创建这个key,当然你也可以使用Primary Database的key值。
为此,你要实现SecondaryKeyCreator接口,这个接口要求你实现SecondaryKeyCreator.createSecondaryKey() 方法。有一点要注意的是,你要抽取的key值是来自于保存于Primary Database中的记录,而在JE中,一条记录键和值都是DatabaseEntry类型的,而且在这个方法中你要生成的key最终也要表现成DatabaseEntry形式,所以你可能需要依赖于Binding API,比如在你使用复杂对象的时候。这个方法的返回值是一个boolean,如果返回false,则说明不存在二级键,这就意味着Primary Database不会填充数据到Secondary Databases中,如果该Secondary Databases有记录,则会被删除。
下面演示下这个过程:
首先假设,我们有个数据库,名叫myPrimaryDatabase,里面存储的记录值是PersonData类型数据,key值是String,同时还有了个自定义的Binding:TupleBinding
public class FullNameKeyCreator implements SecondaryKeyCreator {
private TupleBinding theBinding;
public FullNameKeyCreator(TupleBinding theBinding1) {
theBinding = theBinding1;
}
public boolean createSecondaryKey(SecondaryDatabase secDb,
DatabaseEntry keyEntry,
DatabaseEntry dataEntry,
DatabaseEntry resultEntry) {
try {
PersonData pd = (PersonData) theBinding.entryToObject(dataEntry);
String fullName = pd.getFamiliarName() + " " + pd.getSurname();
resultEntry.setData(fullName.getBytes("UTF-8"));
} catch (IOException willNeverOccur) {}
return true;
}
}
然后我们这样打开和关闭Secondary Datab
DatabaseConfig myDbConfig = new DatabaseConfig();
SecondaryConfig mySecConfig = new SecondaryConfig();
myDbConfig.setAllowCreate(true);
mySecConfig.setAllowCreate(true);
mySecConfig.setSortedDuplicates(true);
Environment myEnv = null;
Database myDb = null;
SecondaryDatabase mySecDb = null;
try {
String dbName = "myPrimaryDatabase";
myEnv = new Environment(new File("/tmp/JEENV"), null);
myDb = myEnv.openDatabase(null, dbName, myDbConfig);
TupleBinding myTupleBinding = new MyTupleBinding();
FullNameKeyCreator keyCreator =
new FullNameKeyCreator(myTupleBinding);
mySecConfig.setKeyCreator(keyCreator);
String secDbName = "mySecondaryDatabase";
mySecDb = myEnv.openSecondaryDatabase(null, secDbName, myDb,
mySecConfig);
} catch (DatabaseException de) {
}finally {
//close的顺序要注意下
try {
if (mySecDb != null) {
mySecDb.close();
}
if (myDb != null) {
myDb.close();
}
if (myEnv != null) {
myEnv.close();
}
} catch (DatabaseException dbe) {
}
}