日期:2014-05-16  浏览次数:20467 次

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) {

    }
}