BerkeleyDB-JE 使用BaseAPI(三)

本篇開始介紹BIND APIs
我們已經知道,要想在JE中讀寫數據,必須藉助DatabaseEntry對象,而原始數據和DatabaseEntry對象之間的轉換,實際上要做的就是把數據轉化爲字節數組或者是把字節數組組裝成數據。除了String類型和布爾型的數據,要進行這樣的轉換則必須使用JE中的BIND APIs。
可以使用BIND APIs的數據基本上分爲三種:
[list]
[*]簡單類型的數據
[*]實現了serialization接口的複雜類型數據
[*]沒有實現serialization接口的複雜類型數據
[/list]
以上三種數據使用BIND APIs的方式是各不相同的。
[b]一.簡單類型的數據[/b]
簡單類型的數據包括了:String,Character,Boolean,Byte,Short,Integer,Long,Float,Double。要想把這類型的數據存儲到DatabaseEntry,有兩個步驟:
1.使用TupleBinding.getPrimitiveBinding返回一個可以轉化相應類型的EntryBinding對象。
2.使用得到的EntryBinding對象把數據放到DatabaseEntry中。
下面演示這個過程

try {
String aKey = "myLong";
DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));

Long myLong = new Long(123456789l);
DatabaseEntry theData = new DatabaseEntry();
EntryBinding myBinding = TupleBinding.getPrimitiveBinding(Long.class);
myBinding.objectToEntry(myLong, theData);

myDatabase.put(null, theKey, theData);
} catch (Exception e) {

}

要想從DatabaseEntry中獲得數據也要藉助EntryBinding對象

try {
String aKey = "myLong";
DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));

DatabaseEntry theData = new DatabaseEntry();
EntryBinding myBinding = TupleBinding.getPrimitiveBinding(Long.class);

if (myDatabase.get(null, theKey, theData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
Long theLong = (Long) myBinding.entryToObject(theData);
retKey = new String(theKey.getData(), "UTF-8");
System.out.println("For key: '" + retKey + "' found Long: '" + theLong + "'.");
}
} catch (Exception e) {

}

[b]二.實現了serialization接口的複雜類型數據[/b]
在實際使用中,像上面那個例子中的數據庫裏的記錄-鍵和值都只是一個簡單類型的字段的情況是很少見的。更常見的是我們會使用複雜類型的對象,它裏面封裝了多個字段。如果這個複雜類型對象實現了serialization接口,我們要把這個數據轉入轉出字節數組,我們可以使用序列化方法(Java serialization),但是這樣不好,最主要的原因是如果這樣做你會存儲非常多無用的信息到JE中。所以我們要使用BIND APIs執行序列化,並且使用BIND APIs仍然會得到序列化對象的所有好處。
使用BIND APIs執行序列化的步驟如下:
1.首先你要讀寫的類必須實現serialization接口。
2.打開兩個database,一個用於保存要讀寫的數據,另外一個用於保存數據的類型信息。
3.創建StoredClassCatalog對象,這個對象代表了一個類型目錄,它需要傳入保存數據的類型信息的數據庫。
4.創建EntryBinding對象,它需要傳入StoredClassCatalog對象和序列化對象的類信息。
5.使用SerialBinding對象把數據放到DatabaseEntry
下面演示這個過程,首先是你要保存到JE的類

public class MyData implements Serializable {
private long longData;
private double doubleData;
private String description;
//省略get和set方法...
}

接下去是你要序列化的方法:

String aKey = "myData";
MyData data2Store = new MyData();
data2Store.setLong(123456789l);
data2Store.setDouble(1234.9876543);
data2Store.setDescription("A test instance of this class");
try {
DatabaseConfig myDbConfig = new DatabaseConfig();
myDbConfig.setAllowCreate(true);
Database myDatabase = myDbEnv.openDatabase(null, "myDb", myDbConfig);
Database myClassDb = myDbEnv.openDatabase(null, "classDb",
myDbConfig);

StoredClassCatalog classCatalog = new StoredClassCatalog(myClassDb);
EntryBinding dataBinding = new SerialBinding(classCatalog,
MyData.class);

DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
DatabaseEntry theData = new DatabaseEntry();
dataBinding.objectToEntry(data2Store, theData);

myDatabase.put(null, theKey, theData);
} catch (Exception e) {

}

下面演示反序列化

String aKey = "myData";
try {
DatabaseConfig myDbConfig = new DatabaseConfig();
myDbConfig.setAllowCreate(false);
Database myDatabase = myDbEnv.openDatabase(null, "myDb", myDbConfig);
Database myClassDb = myDbEnv.openDatabase(null, "classDb",
myDbConfig);
StoredClassCatalog classCatalog = new StoredClassCatalog(myClassDb);
EntryBinding dataBinding = new SerialBinding(classCatalog,
MyData.class);
DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
DatabaseEntry theData = new DatabaseEntry();
myDatabase.get(null, theKey, theData, LockMode.DEFAULT);
MyData retrievedData = (MyData) dataBinding.entryToObject(theData);

} catch (Exception e) {

}

[b]三.沒有實現serialization接口的複雜類型數據[/b]
我們使用自定義的元組綁定(Custom Tuple Bindings)來轉換這類型的數據。必須首先說明的是對於任何類型的數據,包括實現了serialization接口類型的數據仍然可以使用這種方法。而且按照官方文檔上的說明,是推薦對任何複雜類型數據都使用這種方法的。它有以下的優點:
[list]
[*]支持排序,通過序列化得到的字節數組的順序是沒有意義的
[*]壓縮數據量,比序列化得到的字節數組大小上小很多
[*]加速原始數據和字節數組的轉換過程,比序列化轉換來的快
[*]可以使用自定的比較器,使用序列化綁定的方法是無法使用自定義比較器的
[/list]
使用的步驟有:
1.編寫你需要讀寫到JE的類,它可以不用實現serialization接口
2.使用TupleBinding類新建一個元組綁定器(tuple binding)
3.打開數據(只要一個就好)
4.使用你新建的元組綁定器(tuple binding)創建EntryBinding對象
5.使用EntryBinding對象把數據放到DatabaseEntry
下面給出演示:
首先是要讀寫到JE的類

public class MyData2 {
private long longData;
private double doubleData;
private String description;
//省略get和set方法...
}

然後你要必須爲這個類創建一個元組綁定器(tuple binding),你必須繼承TupleBinding類,然後實現兩個抽象方法:TupleBinding.objectToEntry() and TupleBinding.entryToObject()。同時有幾點你要注意:
[list]
[*]使用objectToEntry()方法轉換對象到字節數組。你可以使用TupleOutput轉化原始類型的數據。使用的時候要注意對數值型數據的處理,它只能接受原始類型的數據(比如long, double, int...),而不能處理它們的封裝類型(比如Long, Double, Integer...)。
[*]你使用objectToEntry()方法轉化對象中每個字段的順序關係到對字節數組的排序,以上面的MyData2類爲例,如果轉化的順序是longData,doubleData,description,那麼得到的字節數組就會先按順序的保存這些成員變量,這也意味着你的記錄將先按longData的值來排序,而後是doubleData,最後是description。如果你想按doubleData來排序,那你就必須首先轉化這個成員變量。
[*]使用entryToObject()方法轉換字節數組到對象。你可以使用TupleInput來執行這個轉換。
[*]從字節數組中讀取成員變量的順序必須跟你轉化成員變量到字節數組的順序一致。
[/list]

public class MyTupleBinding extends TupleBinding {
// 轉換對象到字節數組
public void objectToEntry(Object object, TupleOutput to) {
MyData2 myData = (MyData2)object;
to.writeDouble(myData.getDouble().doubleValue());
to.writeLong(myData.getLong());
to.writeString(myData.getString());
}
// 轉換字節數組爲對象
public Object entryToObject(TupleInput ti) {
Double theDouble = new Double(ti.readDouble());
long theLong = ti.readLong();
String theString = ti.readString();
MyData2 myData = new MyData2();
myData.setDouble(theDouble);
myData.setLong(theLong);
myData.setString(theString);
return myData;
}
}

最後你就可以讀寫數據了

TupleBinding keyBinding = new MyTupleBinding();
MyData2 theKeyData = new MyData2();

theKeyData.setLong(123456789l);
theKeyData.setDouble(new Double(12345.6789));
theKeyData.setString("My key data");
DatabaseEntry myKey = new DatabaseEntry();
try {
// Store theKeyData in the DatabaseEntry
keyBinding.objectToEntry(theKeyData, myKey);
...
// Database put and get activity omitted for clarity
...
// Retrieve the key data
theKeyData = (MyData2) keyBinding.entryToObject(myKey);
} catch (Exception e) {
// Exception handling goes here
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章