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