3 JavaのためのSODAの使用
JavaのためのSODAにアクセスする方法、およびこれを使用してコレクションに対する作成、読取り(取得)および削除(CRUD)操作を実行する方法について説明します。
(CRUD操作は、このドキュメントでは読取りおよび書込み操作とも呼ばれています。)
JavaのためのSODAのスタート・ガイド
JavaのためのSODAにアクセスする方法、およびこれを使用してデータベース・コレクションを作成し、ドキュメントをコレクションに挿入し、コレクションからドキュメントを取得する方法について説明します。
ノート:
このトピック内の一部が初見で理解できないことがあっても問題ありません。必要な概念は、別のトピックで詳しくわかるようになっています。このトピックでは、SODAの使用に関する全体的な関連性について説明しています。
次のステップに従って、JavaのためのSODAを開始します。
-
JavaのためのSODAを使用するための前提条件がすべて満たされていることを確認します。「JavaのためのSODAの前提条件」を参照してください。
-
コレクションの格納に使用するデータベース・スキーマ(ユーザー・アカウント)を特定し、データベース・ロール
SODA_APPをそのスキーマに付与します。(ここでプレースホルダuserを実際のアカウント名で置き換えます。)GRANT SODA_APP TO user; -
必要なすべてのjarファイルとファイル
testSoda.java(例3-1のテキストを含む)をディレクトリに配置します。 -
testSoda.javaで次のようにします。-
Oracle Databaseインスタンスに適したホスト名、ポート番号およびサービス名を使用します。(プレースホルダ
host_name、port_numberおよびservice_nameをそれぞれ置き換えます。) -
ステップ2で特定したデータベース・スキーマ(ユーザー・アカウント)の名前とパスワードを使用します。(プレースホルダ
userおよびpasswordを置き換えます。)
-
-
cdコマンドを使用して、jarファイルとファイルtestSoda.javaが含まれているディレクトリに移動します。 -
次のコマンドを実行します。
javac -classpath "*" testSoda.java java -classpath "*:." testSoda2番目のコマンドのかわりに、オプションで次のコマンドを使用できます。これを実行すると、コレクションがドロップされ、コレクションとそのメタデータの格納に使用されるデータベース表がクリーンアップされます。
java -classpath "*:." testSoda dropここで引数
dropを使用すると、コレクションを適切に削除するメソッドdrop()が呼び出されます。注意:
SQLを使用して、コレクションの基礎になっているデータベース表を削除しないでください。コレクションを削除することは、そのデータベース表を削除することで終わりにはなりません。表に格納されるドキュメント以外にも、コレクションにはOracle Databaseに永続化されるメタデータも含まれています。コレクションの基礎になっている表を削除しても、コレクション・メタデータは削除されません。
JavaのためのSODAを使用するには、最初にJDBC接続をオープンする必要があります。これを例3-1に示します。JDBC接続をオープンする方法の詳細は、『Oracle Database JDBC開発者ガイド』を参照してください。
例3-1 testSoda.java
この例では、プレースホルダhost_name、port_number、service_name、userおよびpasswordを、データベース・インスタンスに適したホスト名、ポート番号、サービス名、データベース・スキーマ(ユーザー)名およびパスワードで置き換えます。
import java.sql.Connection;
import java.sql.DriverManager;
import oracle.soda.rdbms.OracleRDBMSClient;
import oracle.soda.OracleDatabase;
import oracle.soda.OracleCursor;
import oracle.soda.OracleCollection;
import oracle.soda.OracleDocument;
import oracle.soda.OracleException;
import java.util.Properties;
public class testSoda
{
public static void main(String[] arg)
{
// Set the JDBC connection string, using information appropriate for your Oracle Database instance.
// (Be sure to replace placeholders host_name, port_number, and service_name in the string.)
String url = "jdbc:oracle:thin:@//host_name:port_number/service_name";
// Set properties user and password.
// (Be sure to replace placeholders user and password with appropriate string values.)
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", password);
Connection conn = null;
try
{
// Get a JDBC connection to an Oracle instance.
conn = DriverManager.getConnection(url, props);
// Enable JDBC implicit statement caching
conn.setImplicitCachingEnabled(true);
conn.setStatementCacheSize(50);
// Get an OracleRDBMSClient - starting point of SODA for Java application.
OracleRDBMSClient cl = new OracleRDBMSClient();
// Get a database.
OracleDatabase db = cl.getDatabase(conn);
// Create a collection with the name "MyJSONCollection".
// This creates a database table, also named "MyJSONCollection", to store the collection.
OracleCollection col = db.admin().createCollection("MyJSONCollection");
// Create a JSON document.
OracleDocument doc =
db.createDocumentFromString("{ \"name\" : \"Alexander\" }");
// Insert the document into a collection.
col.insert(doc);
// Find all documents in the collection.
OracleCursor c = null;
try
{
c = col.find().getCursor();
OracleDocument resultDoc;
while (c.hasNext())
{
// Get the next document.
resultDoc = c.next();
// Print document components
System.out.println ("Key: " + resultDoc.getKey());
System.out.println ("Content: " + resultDoc.getContentAsString());
System.out.println ("Version: " + resultDoc.getVersion());
System.out.println ("Last modified: " + resultDoc.getLastModified());
System.out.println ("Created on: " + resultDoc.getCreatedOn());
System.out.println ("Media: " + resultDoc.getMediaType());
System.out.println ("\n");
}
}
finally
{
// IMPORTANT: YOU MUST CLOSE THE CURSOR TO RELEASE RESOURCES.
if (c != null) c.close();
}
// Drop the collection, deleting the table underlying it and the collection metadata.
if (arg.length > 0 && arg[0].equals("drop")) {
col.admin().drop();
System.out.println ("\nCollection dropped");
}
}
// SODA for Java throws a checked OracleException
catch (OracleException e) { e.printStackTrace(); }
catch (Exception e) { e.printStackTrace(); }
finally
{
try { if (conn != null) conn.close(); }
catch (Exception e) { }
}
}
}SODA for Javaによるドキュメント・コレクションの作成
JavaのためのSODAを使用して新規ドキュメント・コレクションを作成する方法について説明します。
Javaアプリケーションでは、最初にOracleRDBMSClientオブジェクトを作成します。これがJavaのためのSODAを使用するJavaアプリケーションの開始点になります。
OracleRDBMSClient myClient = new OracleRDBMSClient();注意:
OracleRDBMSClientオブジェクトはスレッドセーフです。ただし、他のJavaのためのSODAインタフェースはスレッドセーフではありません。複数のスレッド間でこれらを共有しないでください。
次に、JDBC接続(ここではjdbcConnection)をメソッドOracleClient.getDatabase()に渡して、OracleDatabaseオブジェクト(ここではdb)を取得します。
OracleDatabase db = myClient.getDatabase(jdbcConnection);
ノート:
SODAに渡すJDBC接続に対して暗黙的な文キャッシングを有効にすることをお薦めします。これにより、読取りおよび書込み操作のパフォーマンスを改善できます。読取りおよび書込み操作の基礎となる実装では、JDBCのプリコンパイルされた文が生成されます。
暗黙的なキャッシングを有効にしないと、読取りまたは書込み操作が作成されるたびに、JDBCのプリコンパイルされた新規の文が作成されます。暗黙的なキャッシングを有効にすると、JDBCのプリコンパイルされた新規の文はキャッシュに存在しない場合にのみ作成されます。
関連項目: Oracle Database JDBC開発者ガイドおよびOracle Universal Connection Pool開発者ガイド
コレクションの作成メソッドは、インタフェースOracleDatabaseAdminで使用可能です。このインタフェースにアクセスするには、OracleDatabaseオブジェクト(ここではdb)に対してメソッドadmin()を呼び出します。
OracleDatabaseAdmin dbAdmin = db.admin();
次に、admin()から返されたオブジェクトに対してメソッドcreateCollection()を呼び出し、コレクション名(ここではmyCollection)を文字列として渡すことで、コレクションOracleCollectionオブジェクト(ここではcol)を作成できます。
OracleCollection col = dbAdmin.createCollection("myCollection");
メタデータ引数なしのcreateCollection()メソッドは、Oracle Databaseに次を作成します。
-
永続的なデフォルトのコレクション・メタデータ。
-
入力JDBC接続が構成されているスキーマ内のコレクションを格納するための表。
ノート:
メソッド
createCollection()で使用される表名が、JDBC接続が構成されているスキーマ内の既存の表の名前の場合、メソッドはその表をコレクションにマップしようとします。この動作には表名がコレクション名から派生するデフォルト・ケースがあります。
デフォルトのコレクション・メタデータには次の特性があります。
-
コレクション内の各ドキュメントには次のドキュメント・コンポーネントがあります。
-
キー
-
コンテンツ
-
作成タイムスタンプ
-
最終変更のタイムスタンプ
-
バージョン
-
-
コレクションはJSONドキュメントのみを格納できます。
-
ドキュメント・キーは、コレクションに追加したドキュメントに自動的に生成されます。
ほとんどの場合、デフォルトのコレクション構成をお薦めしますが、コレクションは高度な構成が可能です。コレクションを作成する場合、次のような項目を指定できます。
-
記憶域の詳細。たとえば、コレクションを格納する表の名前、列の名前とデータ型など。
-
作成時のタイムスタンプ、最終変更のタイムスタンプおよびバージョン用の列の有無。
-
コレクションがJSONドキュメントのみを格納できるかどうか。
-
ドキュメント・キーの生成方式、およびドキュメント・キーをクライアントで割り当てるかまたは自動的に生成するか。
-
バージョンの生成方式。
このように構成可能であるため、新規コレクションを既存の表にマップすることもできます。
デフォルトではない方法でコレクションを構成するには、カスタム・コレクション・メタデータ(ここではcollectionMetadata)のJSON OracleDocumentインスタンスを作成し、それをコレクション名の文字列(ここではmyCollection)とともにメソッドcreateCollection()に渡します。
OracleCollection col2 = dbAdmin.createCollection("myCollection", collectionMetadata);
このOracleDocumentインスタンスを容易に作成および生成するには、OracleRDBMSMetadataBuilderを使用できます。
コレクションのストレージおよび構成の詳細に関心がない場合は、例3-2のようにメソッドcreateCollection(myCollection)を使用します。
コレクションがオープンしている場合にのみ、これを検索および変更できます。新しく作成したコレクションがオープンしているのは、セッションの存続期間です。
createCollection()メソッドを起動するときに、同じ名前のコレクションがすでに存在する場合は、単にそのコレクションがオープンされ、そのオブジェクトが返されます。カスタム・メタデータがメソッドに渡され、そのメタデータが既存のコレクションのものと一致しない場合は、コレクションはオープンされずにエラーが発生します。(一致するには、すべてのメタデータ・フィールドが同じ値を保持している必要があります)。
ノート:
特に記載のないかぎり、このドキュメントの残りの部分では、コレクションはデフォルト構成を使用していることを前提としています。
関連項目:
コレクション表のデフォルトのネーミングに関する詳細は、『Oracle Database Simple Oracle Document Access (SODA)の概要』を参照してください
JavaのためのSODAによる既存のドキュメント・コレクションのオープン
OracleDatabaseのメソッドopenCollection()を使用して、既存のドキュメント・コレクションをオープンしたり、特定の名前が既存のコレクションを示すかどうかをテストできます。
例3-2 既存のドキュメント・コレクションのオープン
この例では、myCollectionNameという名前のコレクションをオープンし、このコレクションを表すOracleCollectionオブジェクトを返します。返された値がnullの場合、myCollectionNameという名前のコレクションは存在しません。
OracleCollection col = db.openCollection("myCollectionName");JavaのためのSODAによる指定コレクションの存在の確認
OracleDatabaseのメソッドopenCollection()を使用して、指定したコレクションが存在するかどうかを確認できます。コレクションの引数が既存のコレクションを示さない場合、nullを返し、それ以外の場合、その名前のコレクションをオープンします。
例3-2では、myCollectionNameが既存のコレクションの名前でない場合、ocolには値nullが代入されます。
JavaのためのSODAによる既存のコレクションの検出
OracleDatabaseAdminのメソッドgetCollectionNames()を使用して、既存のコレクションを検出できます。
例3-3 すべての既存のコレクションの名前の出力
この例では、すべての既存のコレクションの名前を出力します。メソッドgetCollectionNames()を最も単純な署名で使用し、引数は受け入れません。
List<String> names = db.admin().getCollectionNames();
for (String name : names)
System.out.println ("Collection name: " + name);JavaのためのSODAによるドキュメント・コレクションのドロップ
OracleCollectionAdminのメソッドdrop()を使用して、ドキュメント・コレクションをドロップします。
注意:
SQLを使用して、コレクションの基礎になっているデータベース表を削除しないでください。コレクションを削除することは、そのデータベース表を削除することで終わりにはなりません。表に格納されるドキュメント以外にも、コレクションにはOracle Databaseに永続化されるメタデータも含まれています。コレクションの基礎になっている表を削除しても、コレクション・メタデータは削除されません。
ノート:
SODAを使用する通常のアプリケーションを日常的に使用する場合、コレクションをドロップして再作成する必要はありません。しかし、なんらかの理由でこれを行う必要がある場合は、このガイドラインが適用されます。
多少なりともコレクションを使用しているアプリケーションがある場合は、コレクションをドロップした後に異なるメタデータで再作成しないでください。すべてのライブSODAオブジェクトが解放されるように、コレクションを再作成する前にこのようなアプリケーションをすべて停止します。
コレクションのドロップだけでは、問題は発生しません。ドロップされたコレクションの読取りまたは書込み操作でエラーが発生します。コレクションをドロップして同じメタデータを持つコレクションを再作成しても、問題はありません。ただし、異なるメタデータでコレクションを再作成して、SODAオブジェクトを使用するライブ・アプリケーションが存在する場合、古いコレクションがアクセスされるというリスクがあり、この場合、エラーは発生しません。
SODA for Javaなど、コレクション・メタデータ・キャッシングを許可するSODA実装では、このようなキャッシュが有効になっている場合に、このリスクが高くなります。その場合、コレクションがドロップされても(共有またはローカルの)キャッシュが古いコレクション・オブジェクトのエントリを返す可能性があります。
ノート:
メソッドdrop()を使用する前に、コレクションへのすべての書込みをコミットしてください。drop()が正常に終了するには、コレクションに対してコミットされていないすべての書込みを最初にコミットする必要があります。そうでない場合は、例外が発生します。
例3-4 ドキュメント・コレクションのドロップ
この例は、コレクションcolを削除します。
col.admin().drop();SODA for Javaによるドキュメントの作成
SODA for Javaによるドキュメントの作成について説明します。
JavaのためのSODAは、JavaインタフェースOracleDocumentを使用したドキュメントを提示します。このインタフェースは主にJSONドキュメントを提示するために設計されていますが、他のコンテンツ・タイプもサポートしています。OracleDocumentオブジェクトが、ドキュメント・コンテンツおよびドキュメント・キーなどのその他のドキュメント・コンポーネントのキャリアです。
OracleDocumentインスタンスにJSONコンテンツを作成するには、好みのパッケージ(JSON処理用のJava APIであるJSR353など)を使用できます。
次に、単純なJSONドキュメントの例を示します。
{ "name" : "Alexander",
"address" : "1234 Main Street",
"city" : "Anytown",
"state" : "CA",
"zip" : "12345"
}ノート:
SODAでは、JSONコンテンツがRFC 4627に準拠する必要があります。さらに、SODA for Javaでは、JSONコンテンツのエンコーディングは、UTF-8またはUTF-16 (ビッグ・エンディアン(BE)またはリトル・エンディアン(LE))のいずれかである必要があります。RFC 4627ではUTF-32 (BEおよびLE)エンコーディングも許可していますが、JavaのためのSODAではこれをサポートしていません。
バイト配列またはStringインスタンスとして表されるコンテンツからOracleDocumentインスタンスを作成するには、(OracleDatabaseによりOracleDocumentFactoryから継承される)次のメソッドをそれぞれ使用します。
-
createDocumentFromByteArray() -
createDocumentFromString()
ドキュメントには次のコンポーネントがあります。
-
キー
-
コンテンツ
-
作成時のタイムスタンプ
-
最終変更のタイムスタンプ
-
バージョン
-
メディア・タイプ(JSONドキュメントの場合、
"application/json")
メソッドcreateDocumentFromString()またはcreateDocumentFromByteArray()を呼び出してドキュメントを作成した場合、次のようになります。
-
メソッドの引数として、ドキュメント・キーを指定する必要があります。
コレクションでは、各ドキュメントにキーが必要です。ドキュメントを作成する場合で、ドキュメントをコレクションに挿入する必要があり、挿入されるドキュメントに対してコレクションで自動的にキーを生成しない場合にのみ、キーを指定する必要があります。デフォルトでは、コレクションは自動的にドキュメント・キーを生成するように構成されます。
-
ドキュメント・コンテンツをメソッドの引数として指定できます(
contentパラメータは必要ですが、値にnullを指定できます)。 -
メソッドでは、作成時タイムスタンプ、最終変更のタイムスタンプおよびバージョンを
nullに設定します。
メソッドcreateDocumentFromString()およびcreateDocumentFromByteArray()には、それぞれ複数のバリアントがあります。
-
最も単純なバリアントはドキュメント・コンテンツのみを受け入れます。メディア・タイプは
"application/json"にデフォルト設定されており、他のコンポーネントはnullにデフォルト設定されています。このバリアントは、ドキュメント・キーを自動的に生成するコレクションに挿入するドキュメントの作成に便利です。 -
別のバリアントでは、ドキュメント・キーとドキュメント・コンテンツの両方を受け入れます。メディア・タイプは
"application/json"にデフォルト設定されており、他のコンポーネントはnullにデフォルト設定されています。このバリアントは、クライアント割当てドキュメント・キーを持つコレクションに挿入するドキュメントの作成に便利です。 -
最も柔軟性の高い(最も詳細な)バリアントでは、キー、コンテンツおよびコンテンツ・タイプを受け入れます。これを使用するとコンテンツ・タイプを指定できるため、このバリアントはJSON以外のドキュメントの作成に便利です。
例3-5では、コンテンツのみを含むOracleDocumentインスタンスを作成します。メディア・タイプは"application/json"にデフォルト設定されており、他のドキュメント・コンポーネントはnullにデフォルト設定されています。
例3-6では、ドキュメント・キーおよびコンテンツを含むOracleDocumentインスタンスを作成します。メディア・タイプは"application/json"にデフォルト設定されており、他のドキュメント・コンポーネントはnullにデフォルト設定されています。
JavaのためのSODAの書込み操作を使用してドキュメントをコレクションに書き込み、JavaのためのSODAの読取り操作を使用してコレクションからドキュメントを読み取ります。
関連項目:
-
メソッド
createDocumentFromString()およびcreateDocumentFromByteArray()に関する詳細は、OracleDocumentFactoryのJavadocを参照してください -
ドキュメント・コンポーネントにアクセスするために使用するgetterメソッドの詳細は、
OracleDocumentのJavadocを参照してください -
SODAドキュメントの概要は、『Oracle Database Simple Oracle Document Access (SODA)の概要』を参照してください
-
SODAドキュメントに適用される制限事項については、『Oracle Database Simple Oracle Document Access (SODA)の概要』を参照してください
例3-5 JSONコンテンツを含むドキュメントの作成
OracleDocument doc =
odb.createDocumentFromString("{ \"name\" : \"Alexander\"}");
// Get the content
String content = doc.getContentAsString();
// Get the content type (it is "application/json")
String contentType = doc.getContentType();
例3-6 ドキュメント・キーおよびJSONコンテンツを含むドキュメントの作成
OracleDocument doc
= odb.createDocumentFromString("myKey", "{ \"name\" : \"Alexander\"}");
JavaのためのSODAによるドキュメントのコレクションへの挿入
ドキュメントをコレクションに挿入するには、OracleCollectionのメソッドinsert(OracleDocument)またはinsertAndGet(OracleDocument)を呼び出します。コレクションがクライアント割当てキーで構成されておらず、入力ドキュメントがキーを指定していない場合、これらのメソッドでは、ドキュメント・キーが自動的に作成されます。
メソッドinsert(OracleDocument)はドキュメントのみをコレクションに挿入します。メソッドinsertAndGet(OracleDocument)では結果のドキュメントも返します。これにはドキュメント・キーおよび他の生成済ドキュメント・コンポーネント(コンテンツを除く)が含まれています。
両方のメソッドでは作成時のタイムスタンプ、最終変更のタイムスタンプおよびバージョンの値が自動的に設定されます(デフォルトの場合と同様にコレクションがこれらのコンポーネントを含めて自動的にバージョンを生成するように構成されている場合)。
ノート:
コレクションがクライアント割当てドキュメント・キーで構成されていて(デフォルトの場合と異なるケース)、入力ドキュメントがコレクション内の既存のドキュメントを識別するキーを提供している場合、これらのメソッドは例外をスローします。例外を発生させるのではなく、入力ドキュメントで既存のドキュメントを置き換える場合、「JavaのためのSODAによるドキュメントのコレクションへの保存」を参照してください。
例3-7では、ドキュメントを作成し、メソッドinsert()を使用してこれをコレクションに挿入します。
例3-8では、ドキュメントを作成し、メソッドinsertAndGet()を使用してこれをコレクションに挿入してから、(コンポーネントが含まれている)結果のドキュメントから生成済コンポーネントをそれぞれ取得します。
多数のドキュメントを1つのコレクションに効率的に挿入するには、OracleCollectionのメソッドinsert(Iterator<OracleDocument>)またはinsertAndGet(Iterator<OracleDocument>)を呼び出します。これらのメソッドはinsert(OracleDocument)およびinsertAndGet(OracleDocument)に類似していますが、単一のドキュメントを処理するのではなく、複数のドキュメントを処理します。パラメータIterator<oracleDocument>は複数の入力ドキュメントに対するイテレータです。
メソッドinsertAndGet(Iterator<OracleDocument>)は結果ドキュメントのリスト(入力ドキュメントごとに1つのOracleDocumentインスタンス)を返します。このような結果ドキュメントには、それぞれドキュメント・キーおよび他の生成済ドキュメント・コンポーネント(コンテンツを除く)が含まれています。結果ドキュメントの順序は入力ドキュメントの順序と同じであり、結果ドキュメントと入力ドキュメントの相互関係を許可します。
insertAndGet()メソッドには、オプションの2番目の引数options(値はJava Map)を受け入れるバリアントがあります。
引数optionsを使用してSQLヒントを提供し、問合せのリアルタイムSQL監視をオンまたはオフにできます。メソッドput()を使用して、値が"MONITOR"のキー"hint"をmap引数に追加します。ヒントは、SODAの下にあるSQLコードに渡されます。
キー"hint"の文字列値では、SQLヒント構文(囲まれたSQLコメント構文/*+...*/のないヒント・テキスト)が使用されます。ヒントMONITOR (監視をオンにする)またはNO_MONITOR (監視をオフにする)のみを使用します。
(これを使用して任意のSQLヒントを渡すことができますが、MONITORとNO_MONITORはSODAに有用なヒントであり、不適切なヒントが原因でオプティマイザによって最適でない問合せ計画が生成される可能性があります。)
関連項目:
-
挿入メソッドの詳細は、
OracleCollectionのJavadocを参照:insert(OracleDocument)insert(Iterator<OracleDocument>)insertAndGet(OracleDocument)insertAndGet(OracleDocument document, Map<String, ?> options)insertAndGet(Iterator<OracleDocument>)insertAndGet(Iterator<OracleDocument> documents, Map<String, ?> options)
-
データベース操作の監視の詳細は、Oracle Database SQLチューニング・ガイドのデータベース操作の監視を参照してください
-
SQLヒント
MONITORおよびNO_MONITORの構文と動作の詳細は、Oracle Database SQLチューニング・ガイドのMONITOR and NO_MONITOR Hintsを参照してください
例3-7 コレクションへのドキュメントの挿入
OracleDocument doc =
db.createDocumentFromString("{ \"name\" : \"Alexander\"}");
col.insert(doc);
例3-8 コレクションへのドキュメントの挿入および結果ドキュメントの取得
OracleDocument doc =
db.createDocumentFromString("{ \"name\" : \"Alexander\"}");
OracleDocument insertedDoc = col.insertAndGet(doc);
// Get the generated document key
String key = insertedDoc.getKey();
// Get the generated creation timestamp
String createdOn = insertedDoc.getCreatedOn();
// Get the generated last-modified timestamp
String lastModified = insertedDoc.getLastModified();
// Get the generated version
String version = insertedDoc.getVersion();
JavaのためのSODAによるドキュメントのコレクションへの保存
OracleCollectionのメソッドsave(OracleDocument)およびsaveAndGet(OracleDocument)を使用して、ドキュメントをコレクションに保存します。
これらのメソッドは、メソッドinsert(OracleDocument)およびinsertAndGet(OracleDocument)と似ていますが、コレクションがクライアント割当てドキュメント・キーで構成されていて、入力ドキュメントがコレクション内のドキュメントを識別するキーを提供している場合、入力ドキュメントが既存のドキュメントを置き換える点が異なります。(この場合、メソッドinsert(OracleDocument)およびinsertAndGet(OracleDocument)は例外をスローします。)
ノート:
デフォルトでは、コレクションは自動的に生成されたドキュメント・キーで構成されます。したがって、デフォルトのコレクションの場合、メソッドsave(OracleDocument)およびsaveAndGet(OracleDocument)は、それぞれメソッドinsert(OracleDocument)およびinsertAndGet(OracleDocument)と等価です。
saveAndGet()メソッドには、オプションの2番目の引数options(値はJava Map)を受け入れるバリアントがあります。
引数optionsを使用してSQLヒントを提供し、問合せのリアルタイムSQL監視をオンまたはオフにできます。メソッドput()を使用して、値が"MONITOR"のキー"hint"をmap引数に追加します。ヒントは、SODAの下にあるSQLコードに渡されます。
キー"hint"の文字列値では、SQLヒント構文(囲まれたSQLコメント構文/*+...*/のないヒント・テキスト)が使用されます。ヒントMONITOR (監視をオンにする)またはNO_MONITOR (監視をオフにする)のみを使用します。
(これを使用して任意のSQLヒントを渡すことができますが、MONITORとNO_MONITORはSODAに有用なヒントであり、不適切なヒントが原因でオプティマイザによって最適でない問合せ計画が生成される可能性があります。)
関連項目:
-
メソッド
save(OracleDocument)、saveAndGet(OracleDocument)およびsaveAndGet(OracleDocument document, Map<String, ?> options)の詳細は、OracleCollectionのJavadocを参照してください -
データベース操作の監視の詳細は、Oracle Database SQLチューニング・ガイドのデータベース操作の監視を参照してください
-
SQLヒント
MONITORおよびNO_MONITORの構文と動作の詳細は、Oracle Database SQLチューニング・ガイドのMONITOR and NO_MONITOR Hintsを参照してください
例3-9 コレクションへのドキュメントの保存
この例では、メソッドsaveAndGet()を使用してクライアント割当てドキュメント・キーで構成されているコレクションにドキュメントを保存します。その後、キーと生成済ドキュメント・コンポーネント(コンテンツを除く)を結果ドキュメント(これらを含む)から取得します。
OracleRDBMSClient cl = new OracleRDBMSClient();
OracleDatabase db = ...
// Configures the collection with client-assigned document keys
OracleDocument collMeta =
cl.createMetadataBuilder().keyColumnAssignmentMethod("client").build();
OracleCollection clientKeysColl = db.createCollection("collectionName",
collMeta);
// For a collection configured with client-assigned document keys,
// you must provide the key for the input document.
OracleDocument cKeyDoc =
db.createDocumentFromString("myKey", "{ \"name\" : \"Alexander\"}");
// If key "myKey" already identifies a document in the collection
// then cKeyDoc replaces the existing doc.
OracleDocument savedDoc = clientKeysColl.saveAndGet(cKeyDoc);
// Get document key ("myKey")
String key = savedDoc.getKey();
// Get the generated creation timestamp
String createdOn = savedDoc.getCreatedOn();
// Get the generated last-modified timestamp
String lastModified = savedDoc.getLastModified();
// Get the generated version
String version = savedDoc.getVersion();SODA for Javaの読取りおよび書込み操作
読取りおよび書込み操作(挿入および保存以外)を指定する第一の方法は、OracleOperationBuilderメソッドをつなげることです。
OracleOperationBuilderでは、次の非ターミナル・メソッドを提供しており、これをつなげて読取りおよび書込み操作を指定できます: key()、keyLike()、keys()、filter()、version()、skip()、limit()およびheaderOnly()。
呼び出されたオブジェクトと同じOracleOperationBuilderオブジェクトを返し、これらのメソッドをつなげることができるため、非ターミナル・メソッドと呼ばれます。非ターミナル・メソッドは操作の一部を指定できますが、操作を作成または実行できません。
OracleOperationBuilderではターミナル・メソッドも提供しています。ターミナル・メソッドは常にメソッド・チェーンの最後に出現し、操作を作成および実行します。
読取り操作のターミナル・メソッドはgetCursor()、getOne()およびcount()です。書込み操作のターミナル・メソッドはreplaceOne()、replaceOneAndGet()およびremove()です。
ノート:
OracleCursorのメソッドnext()またはOracleOperationBuilderのメソッドgetOne()を使用している場合で、基礎となるドキュメントが2GBを超える場合、例外がスローされます。
メソッドのJavadocドキュメントに記述がなければ、すべての非ターミナル・メソッドをつなぎ、ターミナル・メソッドでチェーンを終了できます。ただし、すべての組合せに意味があるわけではありません。たとえば、keys()などのドキュメントを一意に識別しないメソッドとversion()メソッドをつなげても意味はありません。
表3-1では、コレクションに対する操作を構築するためのOracleOperationBuilderの非ターミナル・メソッドについて簡単に説明します。
表3-1 OracleOperationBuilder非ターミナル・メソッド
| メソッド | 説明 |
|---|---|
|
|
指定したドキュメント・キーを持つドキュメントを検索します。 |
|
|
(クライアント割当てキーおよびデータ型 指定されたパターンに一致するキーを持つドキュメントを検索します。 最初のパラメータはパターンで、任意の1文字に一致するワイルドカード 2番目のパラメータがnull以外の場合、 |
|
|
指定した複数のドキュメント・キーを持つ複数のドキュメントを検索します。引数として渡される最大キー数は1000を超えることはできません。そうしないとランタイム・エラーが発生します。 |
|
|
フィルタ仕様(JSONで表される例による問合せ)と一致するドキュメントを検索します。 |
|
|
指定したバージョンのドキュメントを検索します。通常、これは |
|
|
結果からドキュメント・コンテンツを除外します。 |
|
|
結果内で指定した数のドキュメントをスキップします。 |
|
|
結果ドキュメントの数を指定した数に制限します。 |
|
|
SQLチューニング・ヒントを提供して、問合せのリアルタイムSQL監視をオンまたはオフにします。引数は、SQLヒント構文を含む文字列です。これは、引数 (これを使用して任意のSQLヒントを渡すことができますが、 関連項目:
|
表3-2では、コレクションに対して読取り操作を作成および実行するためのOracleOperationBuilderのターミナル・メソッドについて簡単に説明します。
表3-2 読取り操作用のOracleOperationBuilderのターミナル・メソッド
| メソッド | 説明 |
|---|---|
|
|
最大で1つのドキュメントを返す操作を作成および実行します。たとえば、非ターミナル・メソッド |
|
|
読取り操作の結果によってカーソルを取得します。 |
|
|
操作で見つかったドキュメントの数をカウントします。 |
表3-3では、コレクションに対して操作を実行するためのOracleOperationBuilderのターミナル・メソッドについて簡単に説明します。
表3-3 書込み操作のためのOracleOperationBuilderターミナル・メソッド
| メソッド | 説明 |
|---|---|
|
|
1つのドキュメントを置き換えます。 |
|
|
1つのドキュメントを置き換えて、結果ドキュメントを返します。 |
|
|
ドキュメントをコレクションから削除します。 |
関連項目:
-
OracleOperationBuilderのメソッドの詳細は、JavaのためのSODAのJavadocを参照してください -
SODAの制限の詳細は、Oracle Database Simple Oracle Document Access (SODA)の概要を参照してください
JavaのためのSODAによるコレクションでのドキュメントの検索
コレクション内でドキュメントを検索するには、OracleCollectionのメソッドfind()を呼び出します。これは、コレクション内のすべてのドキュメントを検索する問合せを示すOracleOperationBuilderオブジェクトを返します。
問合せを実行するには、OracleOperationBuilderのメソッドgetCursor()を呼び出して、その結果のカーソルを取得します。次に、カーソルを使用して結果リスト内の各ドキュメントにアクセスします。結果リストに次のドキュメントがあるかどうかを判定し、次のドキュメントを取得するには、OracleCursorのメソッドhasNext()およびnext()をそれぞれ呼び出します。これは、例3-10およびその他の例で示されています。
ただし、通常は直接OracleOperationBuilderオブジェクトを使用しても機能しません。かわりに、そのメソッドのいくつかをつなげて様々な検索操作を指定します。これについてはこのガイドの他の例で示します。ここでは、キーまたは例による問合せ(QBE)フィルタ仕様でドキュメントを検索します。
ノート:
メソッドgetContentAsString()を使用する例では、コレクション内のすべてのドキュメントがJSONドキュメントであることを想定しています。そうでない場合、このメソッドは例外をスローします。
例3-10 コレクション内のすべてのドキュメントの検索
この例は、コレクション内の各ドキュメントを含む問合せ結果リストのカーソルを最初に取得します。次にwhile文のカーソルを使用し、結果リスト内の各ドキュメントのコンテンツを文字列として取得して出力します。最後にカーソルをクローズします。
ノート:
リソース・リークを回避するには、不要なカーソルをすべてクローズします。
OracleCursor c = col.find().getCursor();
while (c.hasNext()) {
OracleDocument resultDoc = c.next();
System.out.println("Document content: " +
resultDoc.getContentAsString());
}
// IMPORTANT: You must close the cursor to release resources!
c.close;
例3-11 ドキュメント・キーを付与した一意のドキュメントの検索
この例では、OracleOperationBuilderのメソッドをつなげて、キーが"key1"の一意のドキュメントを検索する操作を指定します。非ターミナル・メソッドkey()を使用してドキュメントを指定します。次に、ターミナル・メソッドgetOne()を使用して、読取り操作を実行してドキュメントを返します(またはドキュメントが見つからない場合、nullを返します)。
OracleDocument doc = col.find().key("key1").getOne();
例3-12 ドキュメント・キーを指定した複数のドキュメントの検索
この例では、(文字列の)キー"key1"、"key2"および"key3"を指定して、HashSet myKeysを定義します。これらのキーを持つドキュメントを検索し、各ドキュメントのキーおよびコンテンツを出力します。
非ターミナル・メソッドkeys()では、特定のキーのドキュメントを指定します。ターミナル・メソッドgetCursor()では、読取り操作を実行し結果ドキュメントを介してカーソルを返します。
ノート:
メソッドkeys()に指定されたセット内のキーの最大数は1000を超えることはできません。そうしないとランタイム・エラーが発生します。
Set<String> myKeys = new HashSet<String>();
myKeys.put("key1");
myKeys.put("key2");
myKeys.put("key3");
OracleCursor c = col.find().keys(myKeys).getCursor();
while (c.hasNext()) {
OracleDocument resultDoc = c.next();
// Print the document key and document content
System.out.println ("Document key: " + resultDoc.getKey() + "\n" +
" document content: " + resultDoc.getContentAsString());
}
c.close();
例3-13 フィルタ仕様によるドキュメントの検索
非ターミナル・メソッドfilter()では、コレクション内のJSONドキュメントをフィルタする強力な方法を提供します。OracleDocumentパラメータはJSONの例による問合せ(QBE、フィルタ仕様とも呼ばれる)です。
フィルタ指定の構文には、表現力のあるJSONドキュメントのパターン・マッチング言語を使用します。この例では、SODA for JavaでどのようにQBEを使用するかを示すために、非常に単純なQBEのみを使用します。
この例では、次の操作を行います。
-
nameフィールドの値が"Alexander"のすべてのJSONドキュメントを検索するフィルタ仕様を作成します。 -
フィルタ仕様を使用して一致するドキュメントを検索します。
-
各ドキュメントのキーおよびコンテンツを出力します。
// Create the filter specification
OracleDocument filterSpec =
db.createDocumentFromString("{ \"name\" : \"Alexander\"}");
OracleCursor c = col.find().filter(filterSpec).getCursor();
while (c.hasNext()) {
OracleDocument resultDoc = c.next();
// Print the document key and document content
System.out.println ("Document key: " + resultDoc.getKey() + "\n" +
" document content: " + resultDoc.getContent());
}
c.close();
関連項目:
-
SODAフィルタ指定に関する概要は、『Oracle Database Simple Oracle Document Access (SODA)の概要』を参照してください
-
SODAフィルタ指定に関するリファレンス情報は、『Oracle Database Simple Oracle Document Access (SODA)の概要』を参照してください
例3-14 メソッドskip()とlimit()を使用したページ区切り問合せの指定
この例では、ページ区切り問合せで非ターミナル・メソッドskip()およびlimit()を使用します。(filterSpecは例3-13のフィルタ仕様です。)
// Find all documents matching the filterSpec, skip the first 1000,
// and limit the number of returned documents to 100.
OracleCursor c =
col.find().filter(filterSpec).skip(1000).limit(100).getCursor();
while (c.hasNext()) {
OracleDocument resultDoc = c.next();
// Print the document key and document content
System.out.println ("Document key: " + resultDoc.getKey() + "\n" +
" document content: " + resultDoc.getContent());
}
c.close();
例3-15 ドキュメント・バージョンの指定
この例では、非ターミナル・メソッドversion()を使用して、ドキュメント・バージョンを指定します。これは、書込み操作用のターミナル・メソッドとともに使用する場合、オプティミスティック・ロックの実装に便利です。
通常、version()は、ドキュメントを指定するkey()メソッドと一緒に使用します。keyLike()メソッドおよびfilter()メソッドとともにversion()を使用することもできます(1つのドキュメントのみが識別される場合)。
// Find a document with key "key1" and version "version1".
OracleDocument doc = col.find().key("key1").version("version1").getOne();
例3-16 ドキュメントの検索およびヘッダーのみの戻し
この例では、指定したドキュメント・キーを持つすべてのドキュメントを検索し、そのヘッダーのみを返します。(キーは、例3-12で定義されているHashSet myKeysにあるものです。)非ターミナル・メソッドheaderOnly()では、ドキュメント・ヘッダーのみを返すことを指定します。ドキュメント・ヘッダーには、コンテンツを除いたすべてのドキュメント・コンポーネントが含まれています。
// Find all documents matching the keys in HashSet myKeys.
// For each document, return all document components except the content.
OracleCursor c = col.find().keys(myKeys).headerOnly().getCursor();
例3-17 見つかったドキュメントの数のカウント
この例では、ターミナル・メソッドcount()を使用して、コレクション内のすべてのドキュメントの数を取得します。次に、例3-13のフィルタ仕様filterSpecによって返されるすべてのドキュメントの数を取得します。
// Get a count of all documents in the collection
int numDocs = col.find().count();
// Get a count of all documents in the collection that match a filter spec
numDocs = col.find().filter(filterSpec).count();
JavaのためのSODAによるコレクション内のドキュメントの置換
コレクション内のドキュメントのコンテンツを別のドキュメントのコンテンツで置き換えるには、OracleOperationBuilderのメソッドkey(String)をメソッドreplaceOne(OracleDocument)またはメソッドreplaceOneAndGet(OracleDocument)につなげます。メソッドreplaceOne(OracleDocument)はドキュメントのみを置き換えます。メソッドreplaceOneAndGet(OracleDocument)は結果ドキュメントも返します。これにはコンテンツ以外のすべてのドキュメント・コンポーネントが含まれています。
replaceOne(OracleDocument)とreplaceOneAndGet(OracleDocument)の両方で最終変更のタイムスタンプおよびバージョンの値を更新します。置き換えてもドキュメント・キーまたは作成時のタイムスタンプは変更されません。
ノート:
デフォルト・メソッドを含め、バージョンを生成する一部のメソッドでは、ドキュメント・コンテンツのハッシュ値を生成します。このような場合、ドキュメント・コンテンツが変更されないと、バージョンも変更されません。バージョンを生成するメソッドの詳細は、「カスタム・メタデータを使用したSODAコレクション構成」を参照してください。
関連項目:
replaceOne()およびreplaceOneAndGet()の詳細は、OracleOperationBuilderのJavadocを参照してください
例3-18 コレクション内のドキュメントの置換えおよび結果ドキュメントの取得
この例では、コレクション内のドキュメントを置き換え、結果ドキュメントを取得し、結果ドキュメントから生成したコンポーネントを取得します。
OracleDocument newDoc = ...
OracleDocument resultDoc = col.find().key("k1").replaceOneAndGet(newDoc);
if (resultDoc != null)
{
// Get the generated document key (unchanged by replacement operation)
String key = resultDoc.getKey();
// Get the generated version
String version = resultDoc.getVersion();
// Get the generated last-modified timestamp
String lastModified = resultDoc.getLastModified();
// Get the creation timestamp (unchanged by replacement operation)
String createdOn = resultDoc.getCreatedOn();
}
例3-19 特定バージョンのドキュメントの置換
ドキュメントを置き換える場合にオプティミスティック・ロックを実装するには、この例のようにメソッドkey()およびversion()をつなげることができます。
OracleDocument resultDoc =
col.find().key("k1").version("v1").replaceOneAndGet(newDoc);JavaのためのSODAによるコレクションからのドキュメントの削除
コレクションからドキュメントを削除するには、(1) OracleCollectionのメソッドfind()を次のOracleOperationBuilderのメソッドにつなげます: (2) key()、keyLike()、keys()またはfilter(); (3) version() (オプション)および(4) remove()。例を示します。
関連項目:
key()、keys()、filter()、version()およびremove()の詳細は、OracleOperationBuilderのJavadocを参照してください
例3-20 ドキュメント・キーによるコレクションからのドキュメントの削除
この例では、ドキュメント・キーが"k1"のドキュメントを削除します。削除したドキュメントの数が返されます。
// Count is 1, if the document with key "k1" is found in the collection.
// Count is 0, otherwise.
int count = col.find().key("k1").remove();
例3-21 特定バージョンのドキュメントの削除
この例では、ドキュメントを削除するときに、ドキュメントのバージョンとそのキーを指定してオプティミスティック・ロックを実装します。
col.find().key("k1").version("v1").remove();例3-22 ドキュメント・キーによるコレクションからのドキュメントの削除
この例では、キーが"k1"および"k2"のドキュメントを削除します。
Set<String> myKeys = new HashSet<String>();
myKeys.add("k1");
myKeys.add("k2");
// Count is 2 if two documents with keys "k1" and "k2"
// were found in the collection.
int count = col.find().keys(myKeys).remove();
例3-23 フィルタによるコレクションからのJSONドキュメントの削除
この例では、フィルタを使用してgreetingフィールドの値が"hello"であるJSONドキュメントを削除します。その後、削除されたドキュメントの数を出力します。
OracleDocument filterSpec =
db.createDocumentFromString("{ \"greeting\" : \"hello\" }");
int count = col.find().filter(filterSpec).remove();
// Print the number of documents removed
System.out.println ("Removed " + count + " documents"):
SODA for Javaによるコレクション内のドキュメントの索引付け
SODAコレクション内のドキュメントの索引付けには、OracleCollectionAdminメソッドcreateIndex()を使用します。そのOracleDocumentパラメータはテキストのJSON索引指定です。これにより、Bツリー、空間、全文または非定型の索引付けを指定し、JSONデータ・ガイドのサポートを指定できます。
ノート:
SODAを使用して任意の種類の索引を作成するには、Oracle Databaseリリース12c (12.2.0.1)以降が必要です。ただし、DATEまたはTIMESTAMP値にBツリー索引を作成するには、Oracle Databaseリリース18c (18.1)以降が必要です。
SODAコレクションの索引の削除には、メソッドdropIndex()を使用します。
JSON検索索引は、全文問合せおよび非定型構造問合せに使用され、永続的な記録およびJSONデータ・ガイド情報の自動更新に使用されます。
Oracle Spatial and Graph索引はGeoJSON (空間)データに使用されます。JSON検索索引は、全文検索およびデータ・ガイド情報の永続化に使用されます。
関連項目:
-
SODA索引の使用の概要については、Oracle Database Simple Oracle Document Access (SODA)の概要を参照
-
SODA索引の仕様に関する情報は、『Oracle Database Simple Oracle Document Access (SODA)の概要』を参照
-
JSON検索索引の詳細は、Oracle Database JSON開発者ガイドを参照
-
JSON検索索引の一部である永続データ・ガイド情報の詳細は、Oracle Database JSON開発者ガイドを参照
-
GeoJSONデータの空間索引付けの詳細は、Oracle Database JSON開発者ガイドを参照してください。
例3-24 SODA for JavaによるJSONフィールドに対するBツリー索引の作成
この例では、コレクションmyCollection内のJSONドキュメントの数値フィールドaddress.zipに対して一意ではないBツリー索引を作成します。
OracleDocument indexSpec =
db.createDocumentFromString(
"{\"name\" : \"ZIPCODE_IDX\",
\"fields\" :
[{\"path\" : \"address.zip\",
\"datatype\" : \"number\",
\"order\" : \"asc\"}]}");
col.admin().createIndex(indexSpec);これは同じ索引指定で、読みやすく印刷されます。
{"name" : "ZIPCODE_IDX",
"fields" : [{"path" : "address.zip",
"datatype" : "number",
"order" : "asc"}]}例3-25 SODA for JavaによるJSON検索索引の作成
この例では、非定型問合せおよび全文検索(QBE演算子$containsを使用した問合せ)のためにコレクションmyCollectionのドキュメントを索引付けし、JSONドキュメントに関するデータ・ガイド情報を自動的に累計および更新します(構造およびタイプ情報を集計します)。索引指定のフィールドはnameのみです(fieldsフィールドは指定しません)。
OracleDocument indexSpec = db.createDocumentFromString(
"{\"name\" : \"SEARCH_AND_DATA_GUIDE_IDX\"}");
col.admin().createIndex(indexSpec);ここで使用されている単純な索引指定は、デフォルト値を明示的に使用した次の指定と同じです。
{"name" : "SEARCH_AND_DATA_GUIDE_IDX",
"dataguide" : "on",
"search_on" : "text_value"}かわりに非定型のみ(検索)の索引付けをする場合は、dataguideフィールドに値"off"を明示的に指定します。かわりにデータ・ガイドのみをサポートする場合は、search_onフィールドに値"none"を明示的に指定します。
ノート:
データ・ガイド対応JSON検索索引を作成する、または既存のJSON検索索引をデータ・ガイド対応にするには、データベース権限CTXAPPおよびOracle Databaseリリース12c (12.2.0.1)以降が必要です。
例3-26 SODA for Javaによる索引の削除
SODAコレクションに対する索引を削除するには、単にOracleCollectionAdminのメソッドdropIndex()に索引名を渡します。この例では、索引myIndexを削除しています。
col.admin().dropIndex("myIndex");コレクションのデータ・ガイドの取得
OracleCollectionAdminのメソッドgetDataGuide()を使用して、コレクションのデータ・ガイドを取得します。データ・ガイドは、コレクション内のJSONドキュメントの構造およびタイプ情報をまとめたJSONドキュメントです。これらの文書内で使用されているフィールドに関するメタデータを記録します。
コレクションのデータ・ガイドを取得する前に、データ・ガイド対応のJSON検索索引を作成する必要があります。この方法を例3-25に示します。
例3-27 JavaのためのSODAによるデータ・ガイドの取得
この例では、OracleCollectionAdminのメソッドgetDataGuide()を使用してデータ・ガイドを取得します。
OracleDocument dataGuide = col.admin().getDataGuide();これは、コンテンツがJSONデータ・ガイドであるドキュメントを返します。このコンテンツを文字列値として取得するには、OracleDocumentのメソッドgetContentAsString()を使用できます。
System.out.println("Dataguide " + dataGuide.getContentAsString());JavaのためのSODAによるトランザクションの処理
JavaのためのSODAが個々の読取りおよび書込み操作またはその操作のグループを単一のトランザクションとして処理するようにすることができます。
メソッドOracleClient.getDatabase()に渡すJDBC接続の自動コミット・モードにはオンまたはオフがあります。
自動コミット・モードがオンの場合、JavaのためのSODAの読取りおよび書込み操作は単一のトランザクションとして処理されます。操作が正常に終了すると、トランザクションは自動的にコミットします。操作が失敗すると、OracleExceptionまたはRuntimeExceptionがスローされ、トランザクションは自動的にロールバックします。SODA for Javaでは確認済の例外(OracleExceptionおよびOracleExceptionから派生した例外)のみをスローします。ただし、JavaのためのSODAはJDBC上で構築されており、JavaのためのSODAが受け渡すRuntimeExceptionをスローできます。
自動コミット・モードがオフの場合、SODA for Javaの複数の読取りまたは書込み操作を1つのトランザクションに結合できます。トランザクションが正常に終了すると、アプリケーションではメソッドcommit()をJDBC接続でコールしてこれを明示的にコミットする必要があります。トランザクションが失敗すると、OracleExceptionまたはRuntimeExceptionがスローされます。アプリケーションでは例外を処理し、メソッドrollback()をJDBC接続上で呼び出して明示的にトランザクションをロールバックする必要があります。(RuntimeExceptionは、前述したようにJDBCでのみスローできます。)
注意:
自動コミット・モードがオフの場合、コミットされていない操作でエラーが発生し、トランザクションを明示的にロールバックしない場合、不完全なトランザクションは、関連データを一貫性のない状態(コミットされていない、部分的な結果)のままにする場合があります。トランザクション・プログラミングを容易にするために、SODA for Javaではオプティミスティック・ロックがサポートされています。データを書き戻す前に、データが読み取られてから(別のトランザクションによって)変更されていないことを確認します。SODA for Javaでは、キーおよびバージョンによる置換または削除、つまりバージョン値のチェックを使用してこれを実行します。例3-19にドキュメントの置換を示し、例3-21にドキュメントの削除を示します。オプティミスティック・ロックは、データの競合が低い状況で特に役立ちます。