表LOBの例
次の例では、表APIを使用して、LOB値を書き込んだ後に読み取ります。オブジェクトがアプリケーション内で実際にマテリアライズ化されることはありませんが、かわりに、値がファイルシステムからストアに直接ストリームされることに注意してください。この簡単な例では、ストアからの読取り時に、取得したバイト数を単純にカウントします。
表APIでLOBを使用する場合でも、LOBオブジェクトを識別するためにKey
を使用する必要があります。つまり、表の行に直接LOBを格納できません。通常、表に格納されている情報を使用してKey
を作成します。たとえば、表セルの1つにLOBキーを単にテキスト文字列として格納できます。または、キーの値を配列(または、マイナー・キー・コンポーネントを使用している場合には2つの配列)として表セルに格納できます。最後に、行の1つ以上のセルから取得した値に基づいてキーを作成できます。
また、この例では最小限の例外ハンドリングのみを示します。本番コードでは、おそらくこの例で拾う例外を単にレポートするよりも多くを実行すると思います。
始める前に、ストアにある表を定義および作成する必要があります。次の表定義ではユーザー情報のとても小さな表を説明します。次に、ユーザーに関連付けられている1つ以上のイメージ・ファイルを識別するために子表を使用します。
table create -name userTable
add-field -type STRING -name userid
add-field -type STRING -name familiarname
add-field -type STRING -name surname
primary-key -field userid -field familiarname -field surname
shard-key -field userid
exit
plan add-table -name userTable -wait
table create -name userTable.images
add-field -type STRING -name imageFileName
add-field -type STRING -name imageVersion
add-field -type STRING -name imageDescription
primary-key -field imageFileName
exit
plan add-table -name userTable.images -wait
ストアに表定義を追加します。
> java -Xmx64m -Xms64m \
-jar KVHOME/lib/kvstore.jar runadmin -host <hostName> \
-port <port> -store <storeName>
kv-> load -file createLOBTable.txt
Table userTable built.
Executed plan 5, waiting for completion...
Plan 5 ended successfully
Table userTable.images built.
Executed plan 6, waiting for completion...
Plan 6 ended successfully
ここまでで表データへの書込みおよび表データからの読取りができるようになりました。次の例では、ユーザー間に3つの関連イメージが存在する2つのユーザーを作成します。最初に表の行が作成(書込み)され、次にBLOBデータがストアに保存されます。例では、次に表全体を反復して関連情報を表示し、途中で各ユーザーに関連付けられているイメージも表示します。この例では、BLOB表示をBLOBのバイト数の単純なレポートのみに限定します。
package kvstore.lobExample;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import oracle.kv.Consistency;
import oracle.kv.Durability;
import oracle.kv.KVStore;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;
import oracle.kv.Key;
import oracle.kv.RequestTimeoutException;
import oracle.kv.Version;
import oracle.kv.lob.InputStreamVersion;
import oracle.kv.lob.PartialLOBException;
import oracle.kv.table.PrimaryKey;
import oracle.kv.table.Row;
import oracle.kv.table.Table;
import oracle.kv.table.TableAPI;
import oracle.kv.table.TableIterator;
import oracle.kv.table.MultiRowOptions;
public class LOBTable {
private String[] hhosts = {"localhost:5000"};
// Store handles
private KVStoreConfig kconfig;
private KVStore kvstore;
// Table handles
private TableAPI tableH;
private Table userTable;
private Table userImageTable;
private Row row;
private static String blobPfx = "blobpfx";
private static String imgSfx = "userimage.lob";
public static void main(String args[]) {
LOBTable lobtable = new LOBTable();
lobtable.run(args);
System.out.println("All done.");
}
private void run(String args[]) {
// Open a store handle
kconfig = new KVStoreConfig("kvstore", hhosts);
kvstore = KVStoreFactory.getStore(kconfig);
tableH = kvstore.getTableAPI();
// Obtain table handles
userTable = tableH.getTable("userTable");
userImageTable = tableH.getTable("userTable.images");
// populate the tables, and load LOBs into the store
addData();
// retrieve tables, and retrieve LOBs from the store
// and show some details about the tables and LOBs.
retrieveData();
}
// Creates some table rows and loads images into the store
private void addData() {
// Load up a couple of rows in the user (parent) table.
row = userTable.createRow();
row.put("userid","m.beckstrom.3267");
row.put("familiarname","Mary");
row.put("surname","Beckstrom");
tableH.put(row, null, null);
row = userTable.createRow();
row.put("userid","h.zwaska.9140");
row.put("familiarname","Harry");
row.put("surname","Zwaska");
tableH.put(row, null, null);
// Now populate each row's image (child) table
// and stream in a BLOB as each row is created.
row = userImageTable.createRow();
row.put("userid","m.beckstrom.3267");
row.put("imageFileName","IMG_2581.jpg");
row.put("imageDescription","Highrise sunset");
tableH.put(row, null, null);
loadBlob("m.beckstrom.3267", "IMG_2581.jpg");
row = userImageTable.createRow();
row.put("userid","m.beckstrom.3267");
row.put("imageFileName","IMG_2607.jpg");
row.put("imageDescription","Swing set at dawn");
tableH.put(row, null, null);
loadBlob("m.beckstrom.3267", "IMG_2607.jpg");
row = userImageTable.createRow();
row.put("userid","h.zwaska.9140");
row.put("imageFileName","mom1.jpg");
row.put("imageDescription","Mom's 89th birthday");
tableH.put(row, null, null);
loadBlob("h.zwaska.9140", "mom1.jpg");
}
// Loads a blob of data into the store
private void loadBlob(String userid, String filename) {
// Construct the key.
// userid and filename are information saved in the
// table, so later we can recreate the key by table
// examination. blobPfx is a constant that we use for
// all BLOB data. imgSfx ends the key path with the
// required suffix. We use a fixed constant partially
// to meet the BLOB suffix requirement, but in a
// larger system this could also be used to
// differentiate the type of data contained in the
// BLOB (image data versus an audio file, for example).
final Key key = Key.createKey(
Arrays.asList(blobPfx, userid, filename, imgSfx));
File lobFile = new File(filename);
try {
FileInputStream fis = new FileInputStream(lobFile);
// The image file is streamed from the filesystem into
// the store without materializing it within the
// application. A medium level of durability is
// used for this put operation. A timeout value
// of 5 seconds is set in which each chunk of the LOB
// must be written, or the operation fails with a
// RequestTimeoutException.
kvstore.putLOB(key, fis,
Durability.COMMIT_WRITE_NO_SYNC,
5, TimeUnit.SECONDS);
} catch (FileNotFoundException fnf) {
System.err.println("Input file not found.");
System.err.println("FileNotFoundException: " +
fnf.toString());
fnf.printStackTrace();
System.exit(-1);
} catch (RequestTimeoutException rte) {
System.err.println("A LOB chunk was either not read or");
System.err.println("not written in the alloted time.");
System.err.println("RequestTimeoutException: " +
rte.toString());
rte.printStackTrace();
System.exit(-1);
} catch (IOException e) {
System.err.println("IO Exception: " + e.toString());
e.printStackTrace();
System.exit(-1);
}
}
// Retrieves the user (parent) table, as well as the images
// (child) table, and then iterates over the user table,
// displaying each row as it is retrieved.
private void retrieveData() {
PrimaryKey key = userTable.createPrimaryKey();
// Iterate over every row in the user table including
// images (child) table in the result set.
MultiRowOptions mro = new MultiRowOptions(null, null,
Arrays.asList(userImageTable));
TableIterator<Row> iter =
tableH.tableIterator(key, mro, null);
try {
while (iter.hasNext()) {
Row row = iter.next();
displayRow(row);
}
} finally {
iter.close();
}
}
// Display a single table row. Tests to see if the
// table row belongs to a user table or a user images
// table, and then displays the row appropriately.
private void displayRow(Row row) {
if (row.getTable().equals(userTable)) {
System.out.println("\nName: " +
row.get("familiarname").asString().get() +
" " +
row.get("surname").asString().get());
System.out.println("UID: " +
row.get("userid").asString().get());
} else if (row.getTable().equals(userImageTable)) {
showBlob(row);
}
}
// Retrieves and displays a BLOB of data. For this limited
// example, the BLOB display is limited to simply reporting
// on its size.
private void showBlob(Row row) {
// Build the blob key based on information stored in the
// row, plus external constants.
String userid = row.get("userid").asString().get();
String filename = row.get("imageFileName").asString().get();
final Key key = Key.createKey(
Arrays.asList(blobPfx, userid, filename, imgSfx));
// Show supporting information about the file which we have
// stored in the table row:
System.out.println("\n\tFile: " + filename);
System.out.println("\tDescription: " +
row.get("imageDescription").asString().get());
try {
// Now read the LOB. It is streamed from the store,
// without materialization within the application code.
// Here, we only count the number of bytes retrieved.
//
// We use the least stringent consistency policy
// available for the read. Each LOB chunk must be read
// within a 5 second window or a RequestTimeoutException
// is thrown.
InputStreamVersion istreamVersion =
kvstore.getLOB(key,
Consistency.NONE_REQUIRED,
5, TimeUnit.SECONDS);
InputStream stream = istreamVersion.getInputStream();
int byteCount = 0;
while (stream.read() != -1) {
byteCount++;
}
System.out.println("\tBLOB size: " + byteCount);
} catch (RequestTimeoutException rte) {
System.err.println("A LOB chunk was either not read or");
System.err.println("not written in the alloted time.");
System.err.println("RequestTimeoutException: " +
rte.toString());
rte.printStackTrace();
System.exit(-1);
} catch (PartialLOBException ple) {
System.err.println("Retrieval (getLOB()) only retrieved");
System.err.println("a portion of the requested object.");
System.err.println("PartialLOBException: " + ple.toString());
ple.printStackTrace();
System.exit(-1);
} catch (IOException e) {
System.err.println("IO Exception: " + e.toString());
e.printStackTrace();
System.exit(-1);
}
}
protected LOBTable() {}
}