主コンテンツへ
Oracle® TimesTen In-Memory Database Java開発者ガイド
リリース18.1
E98630-04
  目次へ移動
目次
索引へ移動
Index

前
 
次
 

2 JDBCでのTimesTenデータベースの使用

この章では、Javaアプリケーションを作成してデータにアクセスする基本的な手順について説明します。TimesTenアプリケーションを作成する前に、前提条件となる次のタスクがすべて完了している必要があります。

前提条件タスク 実行内容
データベースの作成。 TimesTen Classicについては、Oracle TimesTen In-Memory Databaseオペレーション・ガイドのTimesTenデータベースの管理で説明されている手順に従います。

TimesTen Scaleoutについては、Oracle TimesTen In-Memory Database Scaleoutユーザーズ・ガイドのデータベースの作成を参照してください。

Java環境の構成。 「Java開発環境の構成」の手順に従います。
TimesTen Javaのサンプル・アプリケーションのコンパイルおよび実行。 TimesTenクイック・スタートおよびサンプル・アプリケーションを参照してください。

TimesTen Javaのサンプル・アプリケーションを正しく実行すると、開発環境が適切に設定され、データベースにアクセスするアプリケーションの作成の準備が完了します。

この章には、次の各項目が含まれます。

重要なJDBCクラスおよびインタフェース

この項では、重要な標準とTimesTen固有のJDBCパッケージ、クラスおよびインタフェースについて説明します。次の内容を含みます。

標準JDBCの参照情報は、次の場所にあるjava.sqlおよびjavax.sqlパッケージについての情報を参照してください。

https://docs.oracle.com/javase/8/docs/api/java/sql/package-summary.html
https://docs.oracle.com/javase/8/docs/api/javax/sql/package-summary.html

TimesTen JDBC拡張のリファレンス情報は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。


ノート:

TimesTenでは、Java 8 API (JDBC 4.2)がサポートされます。

パッケージのインポート

JDBCを使用するJavaプログラムには、標準のJDBCパッケージをインポートします。

import java.sql.*;

データ・ソースまたはプールされている接続を使用する場合は、標準拡張JDBCパッケージもインポートします。

import javax.sql.*;

TimesTen JDBCパッケージをインポートします。

import com.timesten.jdbc.*;

JTAにXAデータ・ソースを使用するには、このTimesTenパッケージもインポートします。

import com.timesten.jdbc.xa.*;

java.sqlパッケージのインタフェースのサポート

TimesTenでは、表2-1のとおり、java.sqlインタフェースをサポートしています(ここには、TimesTenでのサポートにおける注意事項も記載しています)。

「TimesTen JDBC拡張」も参照してください。

表2-1 サポートされているjava.sqlインタフェース

java.sqlのインタフェース TimesTenでのサポートにおける注意事項

Blob

  • 指定したバイト・パターンまたはBLOBパターンが開始する位置を戻すposition()メソッドはサポートされていません。

CallableStatement

  • 名前ではなく、位置を使用してパラメータをCallableStatementに渡す必要があります。

  • SQLのエスケープ構文は使用できません。

  • これらは、ArrayStructまたはRefではサポートされていません。

  • setDate()getDate()setTime()またはgetTime()Calendarはサポートされていません。

Clob

  • 指定した文字パターンまたはCLOBパターンが開始する位置を戻すposition()メソッドはサポートされていません。

Connection

  • セーブポイントはサポートされていません。

  • TimesTenでは、コミット読取り分離レベルとシリアライズ可能分離レベルがサポートされています。

    setTransactionIsolation(TRANSACTION_READ_COMMITTED);
    
    setTransactionIsolation(TRANSACTION_SERIALIZABLE);
    

    プリフェッチと分離レベル間の関係の詳細は、複数のデータ行のフェッチを参照してください。また、Oracle TimesTen In-Memory Databaseオペレーション・ガイドの分離およびロックによる並行性制御およびOracle TimesTen In-Memory Databaseリファレンスの分離も参照してください。

DatabaseMetaData

  • 制限はありません。

  • supportsRefCursors()メソッドはTRUEを返します。

  • getMaxLogicalLobSize()メソッドは、TimesTenがLOBの論理サイズに使用できる最大バイト数を返します。

Driver

  • TimesTenではjava.util.loggingを使用しないため、getParentLogger()メソッドはSQLFeatureNotSupportedExceptionを返します。(TimesTenドライバはjava.util.logging機能よりも上位にあり、独自のロギング・メカニズムを使用します。)

NClob

  • 指定した文字パターンまたはNCLOBパターンが開始する位置を戻すposition()メソッドはサポートされていません。

ParameterMetaData

  • JDBCドライバは、列がNULL値可能かどうかを判別できません。また、isNullable()へのコールからは、常にparameterNullableUnknownを返します。

  • getScale()メソッドは、VARCHARNVARCHARおよびVARBINARYのデータ型がINLINEの場合、それらに対して1を返します。(スケールは、これらのデータ型では重要ではありません。)

PreparedStatement

  • PreparedStatementgetMetaData()はサポートされていません。

  • これらは、ArrayStructまたはRefではサポートされていません。

  • setObject(java.util.Calendar)およびsetDate(java.util.Date)を使用した設定はTIMESTAMPにマップされます。setDate()getDate()setTime()またはgetTime()Calendar型はサポートされていません。

ResultSet

  • ResultSetでは、getMetaData()をサポートしています。

  • 1つの文に複数のオープンResultSetオブジェクトを持つことはできません。

  • 結果セットの保持可能性は指定できないため、カーソルのコミット後に、そのカーソルをオープンしたままにできません。

  • スクロール可能な結果セットおよび更新可能な結果セットはサポートされていません。

  • これらは、ArrayStructまたはRefではサポートされていません。

  • setDate()getDate()setTime()またはgetTime()Calendar型はサポートされていません。

  • 「TimesTen結果セットの使用: ヒントおよび制限」を参照してください。

ResultSetMetaData

  • getPrecision()メソッドは、精度が未定義の場合に0を返します。

  • getScale()メソッドは、スケールが未定義の場合に-127を返します。

RowId

  • ROWIDデータ型には、RowIdインタフェースを使用してアクセスできます。

  • 出力および入力/出力行IDはTypes.ROWIDとして登録できます。

  • メタデータ・メソッドによって、Types.ROWIDRowIdの適切なものが返されます。

Statement

  • TimesTenでは自動生成キーはサポートされていません。

  • TimesTenでは、cancel()メソッドはODBC関数SQLCancelに委譲します。この関数のTimesTen実装の詳細は、Oracle TimesTen In-Memory Database C開発者ガイドのODBC 2.5の関数サポートを参照してください。この関数はODBC 3.5でもサポートされています。

  • getUpdateCount()メソッドのキャッシュ・グループでの特別なTimesTen機能は、「キャッシュ・グループの管理」を参照してください。

Wrapper

  • TimesTenは、Wrapperを通じてTimesTenConnectionTimesTenCallableStatementTimesTenPreparedStatementおよびTimesTenStatementを公開します。


java.ioパッケージのクラスのサポート

TimesTenによって返されるInputStreamオブジェクトは、マークまたはリセット操作(具体的にはmark()markSupported()およびreset()メソッド)をサポートしていません。

java.sqlパッケージのクラスのサポート

TimesTenでは、これらのjava.sqlクラス(およびSQLExceptionの一部のサブクラス)をサポートしています。

表2-2 サポートされているjava.sqlクラス

java.sqlのインタフェース TimesTenでのサポートにおける注意事項

DataTruncation

注意事項なし

Date

注意事項なし

DriverManager

注意事項なし

DriverPropertyInfo

注意事項なし

Time

TimesTenはTIMEデータ型のTIMEZONEをサポートしていないため、Javaクライアント/サーバー・アプリケーションはサーバーと同じタイム・ゾーンで実行する必要があります。

Timestamp

TIMESTAMPについてもTIMEと同じ考慮事項。

Types

注意事項なし

SQLException

注意事項なし

SQLFeatureNotSupportedException

注意事項なし

SQLWarning

注意事項なし


javax.sqlパッケージのインタフェースとクラスのサポート

TimesTenでは、これらのjavax.sqlインタフェースをサポートしています。

  • CommonDataSourceおよびDataSourceTimesTenDataSourceによって実装されています。

    TimesTenではjava.util.loggingを使用しないため、CommonDataSourceで指定されたgetParentLogger()メソッドはSQLFeatureNotSupportedExceptionを返します。(TimesTenドライバはjava.util.logging機能よりも上位にあり、独自のロギング・メカニズムを使用します。)

  • PooledConnectionは、ObservableConnectionで実装されています。

  • ConnectionPoolDataSourceObservableConnectionDSで実装されています。

  • XADataSourceTimesTenXADataSource(com.timesten.jdbc.xaパッケージ内)で実装されています。


重要:

TimesTen JDBCドライバ自身は、データベース接続プールを実装していません。ObservableConnectionおよびObservableConnectionDSクラスは、標準Java EEインタフェースを実装しているだけであり、Java EE標準に基づいたデータベース接続プールの作成および管理を簡単に行えます。

TimesTenではこのjavax.sqlイベント・リスナーをサポートしています。

  • PooledConnectionインスタンスの使用時、ConnectionEventListenerインスタンスを登録しConnectionEventの出現をリスニングできます。


ノート:

TimesTenではStatementEventListenerインスタンスは登録できますが、StatementEventインスタンスはサポートされていません。

TimesTen JDBC拡張

ほとんどの場合、TimesTenでサポートされている標準JDBC機能を使用することができます。

また、TimesTen固有の機能のためのcom.timesten.jdbcパッケージには、表2-3に示す拡張機能もあります。

表2-3 TimesTen JDBC拡張

インタフェース 拡張 注意事項

TimesTenBlob

Blob

BlobインスタンスはTimesTenBlobにキャストできます。これには、LOBがOracle DatabaseパススルーLOBであるかを示したり、LOBリソースを解放したり、位置と長さの指定とともにバイナリ・ストリームを取得する機能があります。

「LOBの作業」を参照してください。

TimesTenCallableStatement

CallableStatement

java.sql.Wrapperにより公開されます。

PL/SQL REF CURSORのサポート。「REF CURSORの使用」を参照してください。

入力パラメータを設定し出力パラメータを取得および登録するメソッドとともに、連想配列バインドをサポートしています。「連想配列のバインド」を参照してください。

TimesTenClob

Clob

ClobインスタンスはTimesTenClobにキャストできます。これには、LOBがOracle DatabaseパススルーLOBであるかを示したり、LOBリソースを解放したり、位置と長さの指定とともに文字のストリームを取得する機能があります。

「LOBの作業」を参照してください。

TimesTenConnection

Connection

java.sql.Wrapperにより公開されます。

これには、パフォーマンス向上のための行のプリフェッチ、問合せのパフォーマンスの最適化、自動クライアント・フェイルオーバーのためのイベントのリスニング、レプリケーション・トラックを指定するパラレル・レプリケーション・スキームのためのトラック番号の設定、データベースの妥当性確認の機能が含まれます。

「複数のデータ行のフェッチ」「問合せのパフォーマンスの最適化」「一般的なクライアント・フェイルオーバー機能」「レプリケーションで使用する機能」「データベースの妥当性の確認」を参照してください。

TimesTenNClob

NClob

NClobインスタンスはTimesTenNClobにキャストできます。これには、LOBがOracle DatabaseパススルーLOBであるかどうかを示す機能を含みます。

「LOBの作業」を参照してください。

TimesTenPreparedStatement

PreparedStatement

java.sql.Wrapperにより公開されます。

DML RETURNINGのサポート。「DML RETURNINGの使用(RETURNING INTO句)」を参照してください。

入力パラメータを設定するメソッドとともに連想配列のバインドをサポートしています。「連想配列のバインド」を参照してください。

TimesTenStatement

Statement

java.sql.Wrapperにより公開されます。

問合せのしきい値を指定する機能を提供します。「SQL文のしきい値期間の設定」を参照してください。


その他のTimesTenクラスおよびインタフェース

前述の実装に加えて、com.timesten.jdbcパッケージには、インタフェースおよびクラスがあります。これらのインタフェースおよびクラスでサポートされた機能は、この章の後半で説明します。

その他のTimesTenインタフェース

  • TimesTen型の拡張(TimesTen REF CURSORなど)にTimesTenTypesを使用します。

  • 自動クライアント・フェイルオーバー機能に、ClientFailoverEventListener(および次に説明するClientFailoverEventクラス)を使用します。「自動クライアント・フェイルオーバーのJDBCサポート」を参照してください。

  • SQL例外に使用されるベンダー・コードに、TimesTenVendorCodeを使用します。

  • TimesTen Scaleoutでのクライアント・ルーティングにTimesTenDistributionKeyおよびTimesTenDistributionKeyBuilderを使用します。TimesTen Scaleoutでのクライアント・ルーティングを参照してください。

  • TimesTenConnectionBuilderを使用して、分散キー、要素IDまたはレプリカ・セットIDに基づいて最適な要素に接続します。分散キーに基づいた要素への接続を参照してください。

その他のTimesTenクラス

  • 自動クライアント・フェイルオーバー機能に、ClientFailoverEvent(および前述のClientFailoverEventListenerインタフェース)を使用します。

TimesTenデータベース接続の管理

作成するDSNのタイプは、アプリケーションがデータベースに直接接続するか、クライアント接続するかによって異なります。

TimesTen Scaleoutの場合、直接接続またはクライアント/サーバー接続のいずれかを使用したデータベースの作成と接続の詳細は、Oracle TimesTen In-Memory Database Scaleoutユーザーズ・ガイドを参照してください。データベースの作成およびデータベースへの接続を参照してください。

TimesTen Classicの場合、データベースに直接接続する場合は、Oracle TimesTen In-Memory Databaseオペレーション・ガイドのLinuxおよびUNIXでのDSNの作成(TimesTen Classicの場合)の説明に従ってDSNを作成します。データベースへのクライアント接続を作成する場合は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のWindowsでのクライアントDSNの作成および構成に関する項またはLinuxおよびUNIXでのクライアントDSNの作成および構成に関する項に従ってDSNを作成してください。

DSNを作成すると、アプリケーションはデータベースに接続できます。この項では、JDBC直接ドライバまたはJDBCクライアント・ドライバを使用して、データベースへのJDBC接続を作成する方法について説明します。

この項で説明する操作は、level1サンプル・アプリケーションに基づいています。TimesTenクイック・スタートおよびサンプル・アプリケーションを参照してください。


ノート:

TimesTenでは、標準のjava.sql.Wrapper機能を介してTimesTen固有の実装を公開します。Wrapperを使用してTimesTenConnectionインタフェースを実装する接続オブジェクトを取得し、TimesTen固有の機能にアクセスできるようにできます。次の例では、TimesTenConnectionオブジェクトを返し、それからTimesTenの拡張であるsetReplicationTrack()メソッドを呼び出しています。
String databaseUrl = null;
...
Connection conn = DriverManager.getConnection(databaseUrl);
If (conn.isWrapperFor(TimesTenConnection.class) ) {
  TimesTenConnection tconn = conn.unwrap(TimesTenConnection.class);
  tconn.setReplicationTrack(4);
}
...

内容は次のとおりです。

データベースの接続URLの作成および接続属性の指定

JDBC接続を作成するには、データベースのTimesTen接続URLを指定します。TimesTen接続URLの形式は、次のとおりです。

jdbc:timesten:{direct|client}:dsn=DSNname;[DSNattributes;]

デフォルトはdirectです。

たとえば、サンプル・データベースへの直接接続を次のように作成します。

String URL = "jdbc:timesten:direct:dsn=sampledb";

接続URLに属性を指定して、DSNの記述に接続属性をプログラム的に設定または上書きすることができます。

接続属性の概要については、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のData Manager DSNまたはサーバーDSNの接続属性に関する説明を参照してください。一般的な接続属性に特別な権限は必要ありません。データベースが最初にロードされたときに、最初の接続属性が設定された後、すべての接続で有効になります。インスタンス管理者のみが、データベースをロードして最初の接続属性の設定を変更できます。特定の接続属性(必要な権限を含む)の詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』の接続属性に関する説明を参照してください。

たとえば、LockLevelの一般的な接続属性を1に設定するには、次のようにURLを作成します。

String URL = "jdbc:timesten:direct:dsn=sampledb;LockLevel=1";

データベースへの接続

URLを定義したら、DriverManagerまたはTimesTenDataSourceのいずれかのgetConnection()メソッドを使用し、データベースに接続します。

DriverManager.getConnection()メソッドを使用する場合は、データベースに接続するドライバURLを指定します。

import java.sql.*;
...
Connection conn = DriverManager.getConnection(URL);

TimesTenDataSourceメソッドgetConnection()を使用するには、まずデータ・ソースを作成します。次に、TimesTenDataSourceメソッドsetUrl()を使用してURLを設定し、getConnection()を使用して接続します。

import com.timesten.jdbc.TimesTenDataSource;
import java.sql.*;
...

TimesTenDataSource ds = new TimesTenDataSource();
ds.setUrl("jdbc:timesten:direct:<dsn>");
Connection conn = ds.getConnection();

TimesTenユーザー名およびパスワードは、setUrl()コールのURLのDSNに設定できますが、これを別に設定したり、Oracle Databaseパスワードを設定する(該当する場合)TimesTenDataSourceメソッドもあります。

TimesTenDataSource ds = new TimesTenDataSource();
ds.setUser(myttusername);                    // User name to log in to TimesTen
ds.setPassword(ttpassword);                  // Password to log in to TimesTen
ds.setUrl("jdbc:timesten:direct:<dsn>");
ds.setOraclePassword(oraclepassword);        // Password to log in to Oracle DB
Connection conn = ds.getConnection();

DriverManager.getConnection()メソッドまたはds.getConnection()メソッドのいずれかによって、データベースへのハンドルとして利用できるConnectionオブジェクト(この例ではconn)が返されます。DriverManagerメソッドgetConnection()の使用例についてはlevel1サンプル・アプリケーションを、TimesTenDataSourceメソッドgetConnection()の使用例についてはlevel2およびlevel3サンプル・アプリケーションを参照してください。TimesTenクイック・スタートおよびサンプル・アプリケーションを参照してください。

データベースからの切断

データベースにアクセスする必要がなくなった場合、通常はConnectionメソッドclose()をコールし、データベースへの接続をクローズします。

TimesTen接続はまた、標準のabort()メソッドに加え、java.lang.AutoCloseableを使用した標準のtry-with-resource機能もサポートしています。

エラーが発生した場合は、データベースから切断する前に、トランザクションをロールバックできます。詳細は、「致命的ではないエラーの処理」および「失敗したトランザクションのロールバック」を参照してください。

直接接続のオープンおよびクローズ

例2-1に、サンプル・データベースへの直接接続を作成し、いくつかのSQLを実行し、その後接続をクローズするためにDriverManagerクラスを使用するアプリケーションの一般的なフレームワークを示します。実際の例については、level1サンプル・アプリケーションを参照してください。(サンプル・アプリケーションについてはTimesTenクイック・スタートおよびサンプル・アプリケーションを参照してください。)

例2-1 接続、SQLの実行、切断

String URL = "jdbc:timesten:dsn=sampledb";
Connection conn = null;

try {
     Class.forName("com.timesten.jdbc.TimesTenDriver");
} catch (ClassNotFoundException ex) {
      // See "Handling errors"
}

try {
    // Open a connection to TimesTen
    conn = DriverManager.getConnection(URL);

    // Report any SQLWarnings on the connection
    // See "Reporting errors and warnings"

    // Do SQL operations
    // See "Managing TimesTen data" below

    // Close the connection to TimesTen
    conn.close();

// Handle any errors
} catch (SQLException ex) {
    // See "Handling errors"
}

データベースの妥当性の確認

アプリケーションは次のTimesTenConnectionメソッドをコールして、データベースが妥当であるかを検出できます。

boolean isDataStoreValid() throws java.sql.SQLException

データベースが妥当な場合にはtrueが返され、システムまたはアプリケーションの障害などによりデータベースが無効な場合にはfalseが返されます。

TimesTenデータの管理

この項では、TimesTenデータベースでのデータの操作方法の詳細情報を説明します。


ノート:

TimesTenでは、標準のjava.sql.Wrapper機能を介してTimesTen固有の実装を公開します。Wrapperを使用してTimesTenStatementTimesTenPreparedStatementおよびTimesTenCallableStatementインタフェースを実装する文オブジェクトを取得し、TimesTen固有の機能にアクセスできるようにできます。同様の説明および接続オブジェクトに関する例は、TimesTenデータベース接続の管理を参照してください。

この項には、次の項目について説明します。

単純なSQL文の実行

SQLを使用してデータを管理する方法については、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTenデータベースのデータの処理に関する説明を参照してください。この項では、ConnectionインスタンスのcreateStatement()メソッド、およびStatementインスタンスのexecuteUpdate()メソッドまたはexecuteQuery()メソッドを使用して、Javaアプリケーション内でSQL文を実行する方法について説明します。

事前に文が準備されていない場合は、SQL文の特性および返された結果セットに応じて、execute()executeUpdate()executeQuery()などのStatementオブジェクトの実行メソッドを使用します。

事前に準備されたSQL文には、PreparedStatementオブジェクトの同じ実行メソッドを使用します。

execute()メソッドは、結果セットがある場合はtrueを返し(SELECTなど)、結果セットがない場合はfalseを返します(INSERTUPDATEDELETEなど)。executeUpdate()メソッドは、影響を受ける行数を返します。たとえば、INSERT文を実行すると、executeUpdate()メソッドは挿入された行数を返します。executeQuery()メソッドは結果セットを返すため、(SELECT文の実行時など)結果セットが必要な場合にのみコールする必要があります。


ノート:

TimesTenで生成された結果セットの使用に関する注意事項は、「TimesTen結果セットの使用: ヒントおよび制限」を参照してください。

例2-2 更新の実行

この例では、StatementオブジェクトでexecuteUpdate()メソッドを使用して、現在のスキーマのcustomer表にデータを挿入するINSERT文を実行します。示されてはいませんが、この接続はオープンされている必要があります。

Connection conn = null;
Statement stmt = null;
...
// [Code to open connection. See "Connect to the database"...] 
...
try {
    stmt = conn.createStatement();
    int numRows = stmt.executeUpdate("insert into customer values" 
                  + "(40, 'West', 'Big Dish', '123 Signal St.')");
}
catch (SQLException ex) {
    ...
}

例2-3 問合せの実行

この例では、StatementオブジェクトでexecuteQuery()コールを使用し、現在のスキーマのcustomer表にSELECT文を実行して、返されたjava.sql.ResultSetインスタンスを表示します。

Statement stmt = null;
. . . . . .
try {
  ResultSet rs = stmt.executeQuery("select cust_num, region, " +
                      "name, address from customer");
  System.out.println("Fetching result set...");
  while (rs.next()) {
    System.out.println("\n Customer number: " + rs.getInt(1));
    System.out.println(" Region: " + rs.getString(2));
    System.out.println(" Name: " + rs.getString(3));
    System.out.println(" Address: " + rs.getString(4));
    }
  } 
catch (SQLException ex) {
  ex.printStackTrace();
}

TimesTen結果セットの使用: ヒントおよび制限

ResultSetオブジェクトを使用して、問合せ結果を処理します。また、一部のメソッドおよび組込みプロシージャは、ResultSetオブジェクトの形式でTimesTenデータを返します。この項では、TimesTenからのResultSetオブジェクトの使用について説明します。


重要:

TimesTenでは、コミットやロールバックなど、トランザクションを終了する操作は、接続に関連付けられているすべてのカーソルをクローズします。

  • TimesTenでは、1つの文で複数のResultSetオブジェクトをオープンすることはできません。また、1つのStatementオブジェクトから、現行結果セットをクローズせずに複数のResultSetオブジェクトを返すことはできません。

  • TimesTenでは、保持可能なカーソルはサポートされていません。結果セットの保持可能性(つまり、カーソルのコミット後に、そのカーソルをオープンしたままにできるかどうか)は指定できません。

  • ResultSetオブジェクトをスクロールまたは更新できないため、ResultSet.TYPE_SCROLL_SENSITIVEまたはResultSet.CONCUR_UPDATABLEは指定できません。

  • 通常は、ResultSetメソッドclose()を使用して、処理後すぐに結果セットをクローズできます。パフォーマンス上の理由から、これは読取りおよび更新処理で使用される結果セットおよびプール接続で使用される結果セットで特に重要です。

    TimesTen結果セットはまた、java.lang.AutoCloseableを使用した標準のtry-with-resource機能もサポートしています。

  • 基礎となるデータ型が文字列ではない場合、ResultSetメソッドgetString()をコールすると、パフォーマンスの点でコストが高くなります。Javaの文字列は不変的であるため、getString()は、コールされるたびに新しい文字列用に領域を確保する必要があります。したがって、必要な場合を除き、byteintなどの基本的な数値型の取得にgetString()を使用しないでください。たとえば、整数列の場合、getInt()をコールする方が大幅に高速に処理が実行されます。「ResultSetメソッドgetString()の限定的使用」も参照してください。

    また、日付およびタイムスタンプの場合、ResultSetのネイティブ・メソッドgetDate()およびgetTimestamp()の方がgetString()よりもパフォーマンスに優れています。

  • getXXX()コールの選択および起動後の必要なデータ変換は、アプリケーション・パフォーマンスに影響を与えます。

  • JDBCはConnectionCharacterSet属性の設定を無視します。データはUTF-16エンコードで返されます。

複数のデータ行のフェッチ

複数のデータ行をフェッチすると、コミット読取り分離レベルが設定されたデータベースに接続しているクライアント/サーバー・アプリケーションのパフォーマンスを向上させることができます。

プリフェッチされる行数を指定するには、次の手順を実行します。

  • StatementまたはResultSetメソッドsetFetchSize()をコールします。これらのメソッドは標準のJDBCコールですが、1回の実行で効果があるのは1つの文のみであるという制限があります。

  • TimesTenConnectionメソッドsetTtPrefetchCount()をコールします。これにより、ある接続に対するすべての文で同じプリフェッチ設定が使用されるように、その接続レベルでのプリフェッチを確立するTimesTenの拡張が有効になります。

この項では、TimesTenで実装されている接続レベルのプリフェッチについて説明します。


ノート:

TimesTenのプリフェッチ数を拡張しても、データベースへの直接接続を使用するアプリケーションにとってメリットはありません。

プリフェッチ数を0(ゼロ)に設定すると、TimesTenはデータベースに設定した分離レベルに応じてデフォルトのプリフェッチ数を使用し、プリフェッチ数をその値に設定します。コミット読取り分離レベルでは、デフォルトのプリフェッチの値は5です。シリアライズ可能分離レベルでは、デフォルトは128です。デフォルトのプリフェッチの値はほとんどのアプリケーションに最適な設定です。一般的に、値を高く設定すると、リソースの使用量がわずかに増加しますが、大きい結果セットに対するパフォーマンスは向上する可能性があります。

プリフェッチを無効にするには、プリフェッチ数を1に設定します。

TimesTenConnectionメソッドgetTtPrefetchCount()をコールして、現行のプリフェッチ値を確認します。

トランザクション分離レベルの設定の詳細は、java.sqlパッケージのインタフェースのサポートConnectionインタフェース・エントリを参照してください。詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

例2-4 プリフェッチ・カウントの設定

次のコードでは、setTtPrefetchCount()コールを使用して、プリフェッチ数を10に設定し、getTtPrefetchCount()コールを使用して、カウント変数のプリフェッチ数を返します。

TimesTenConnection conn =
    (TimesTenConnection) DriverManager.getConnection(url);

// set prefetch count to 10 for this connection
conn.setTtPrefetchCount(10);

// Return the prefetch count to the 'count' variable.
int count = conn.getTtPrefetchCount();

問合せのパフォーマンスの最適化

TimesTen拡張機能を使用すると、アプリケーションでは、trueを設定してTimesTenConnectionメソッドのsetTtPrefetchClose()をコールすることにより、クライアント/サーバー・アプリケーションの読取り専用問合せのパフォーマンスを最適化できます。

すべてのトランザクションは、読取り専用トランザクションを含め、実行時にコミットされる必要があります。setTtPrefetchClose(true)コールでは、サーバーはカーソルを自動的にクローズして、サーバーが読取り専用問合せの結果セットのすべての行をプリフェッチした後でトランザクションをコミットします。これによって、クライアントとサーバー間のネットワーク・ラウンドトリップ数が減少するため、パフォーマンスが向上します。

クライアントでは、依然として結果セットをクローズしてトランザクションをコミットする必要がありますが、これらのコールはクライアントで実行されるため、クライアントとサーバー間のネットワーク・ラウンドトリップを必要としません。


ノート:

  • setTtPrefetchClose(true)コールを使用した同じ接続に対して複数の文ハンドルを使用しないでください。サーバーでは、クライアントが終了する前に、結果セットのすべての行がフェッチされ、トランザクションがコミットされて文ハンドルがクローズされる可能性があります。これにより、すべての文ハンドルが閉じられます。

  • TimesTen直接接続およびSELECT FOR UPDATE文の場合、true設定は無視されます。

  • getTtPrefetchClose()を使用して、現在の設定(trueまたはfalse)を取得します。


次の例に、setTtPrefetchClose(true)の使用方法を示します。

import com.timesten.sql;
...
con = DriverManager.getConnection ("jdbc:timesten:client:" + DSN);
stmt = con.createStatement();
...
con.setTtPrefetchClose(true);
rs = stmt.executeQuery("select * from t");
while(rs.next())
{
// do the processing
}
rs.close();
con.commit();

パラメータのバインドと文の実行

この項では、SQL文の入力または出力パラメータをバインドする方法について説明します。内容は次のとおりです。


ノート:

  • 通常、StatementPreparedStatementまたはCallableStatementのメソッドclose()を使用して、使用が終わった文をクローズします。TimesTen文セットはまた、java.lang.AutoCloseableを使用した標準のtry-with-resource機能もサポートしています。

  • TimesTen開発者ガイドで使用される「バインド・パラメータ」という用語(ODBC用語に準拠)は、TimesTenのPL/SQLのマニュアルで使用される「バインド変数」という用語(Oracle Database PL/SQL用語に準拠)と同じです。


SQL文の準備および入力パラメータの設定

複数回実行するSQL文は、ConnectionメソッドprepareStatement()をコールして事前に準備しておく必要があります。最大のパフォーマンスを得るために、パラメータを使用した文を準備します。

次のことに注意してください。

  • TimesTenのバインド・メカニズム(アーリー・バインディング)はOracle Databaseのバインド・メカニズム(レイト・バインディング)とは異なります。TimesTenは、問合せの準備の前にデータ型を必要とします。そのため、各バインド・パラメータのデータ型が指定されていないかSQL文から推測できないと、エラーが発生します。たとえば次のような文が、これに該当します。

    SELECT 'x' FROM DUAL WHERE ? = ?;
    

    この問題には、たとえば次のように対処できます。

    SELECT 'x' from DUAL WHERE CAST(? as VARCHAR2(10)) = CAST(? as VARCHAR2(10));
    
  • デフォルトでは(接続属性PrivateCommands=0の場合)、TimesTenは接続間で準備された文を共有するため、様々な接続での同じ文の後続の準備は非常に迅速に実行されます。

  • setXXX()コールの選択および起動前の必要なデータ変換の選択は、アプリケーション・パフォーマンスに影響を与えます。たとえば、時刻、日付およびタイムスタンプでは、PreparedStatementのネイティブ・メソッドsetTime()setDate()およびsetTimestamp()は、setString()よりもパフォーマンスに優れています。

  • TT_TINYINT列では、TT_TINYINT (0から255)の範囲を完全に使用するために、setByte()のかわりにsetShort()またはsetInt()を使用します。

  • setObject(java.util.Calendar)およびsetDate(java.util.Date)を使用した設定はTIMESTAMPにマップされます。

例2-5 問合せのための準備された文

この例では、PreparedStatementオブジェクトでの基本的なexecuteQuery()コールを示します。これは、準備済のSELECT文を実行して、返された結果セットを表示します。

PreparedStatement pSel = conn.prepareStatement("select cust_num, " +
                         "region, name, address " +
                         "from customer" +
                         "where region = ?");
pSel.setInt(1,1);

try {
  ResultSet rs = pSel.executeQuery();

  while (rs.next()) {
    System.out.println("\n Customer number: " + rs.getInt(1));
    System.out.println(" Region: " + rs.getString(2));
    System.out.println(" Name: " + rs.getString(3));
    System.out.println(" Address: " + rs.getString(4));
  }
} 
catch (SQLException ex) {
   ex.printStackTrace();
}

例2-6 更新のための準備された文

次の例に、4つの別々の文のかわりに、パラメータを使用した単一の文を使用する方法を示します。

値が異なる同様のINSERT文の実行:

Statement.execute("insert into t1 values (1, 2)");
Statement.execute("insert into t1 values (3, 4)");
Statement.execute("insert into t1 values (5, 6)");
Statement.execute("insert into t1 values (7, 8)");

パラメータを使用した単一のINSERT文を準備し、PreparedStatementメソッドsetXXX()を使用して、各文を実行する前に行の値を設定する方がより効率的です。

PreparedStatement pIns = conn.PreparedStatement("insert into t1 values (?,?)");

pIns.setInt(1, 1);
pIns.setInt(2, 2);
pIns.executeUpdate();

pIns.setInt(1, 3);
pIns.setInt(2, 4);
pIns.executeUpdate();

pIns.setInt(1, 5);
pIns.setInt(2, 6);
pIns.executeUpdate();

pIns.setInt(1, 7);
pIns.setInt(2, 8);
pIns.executeUpdate();

conn.commit();
pIns.close();

TimesTenでは、準備された文がコミットされると、自動的に共有されます。たとえば、データベースへの2つ以上の別々の接続が、それぞれ同じ文を、1個、2個、3個、...、n個準備した場合、TimesTenは最初に準備した文を覚えているため、n番目の準備はとても早く返されます。

例2-7 更新および問合せのための準備された文

この例では、INSERT文とSELECT文を準備し、INSERTを2回実行し、SELECTを実行し、返された結果セットを出力します。実際の例については、level1サンプル・アプリケーションを参照してください。(サンプル・アプリケーションについてはTimesTenクイック・スタートおよびサンプル・アプリケーションを参照してください。)

Connection conn = null;
...
// [Code to open connection. See "Connect to the database"...]
...

// Disable auto-commit
conn.setAutoCommit(false);

    // Report any SQLWarnings on the connection
    // See "Reporting errors and warnings"

// Prepare a parameterized INSERT and a SELECT Statement
PreparedStatement pIns = 
                  conn.prepareStatement("insert into customer values (?,?,?,?)");

PreparedStatement pSel = conn.prepareStatement
    ("select cust_num, region, name, " +
    "address from customer");

// Data for first INSERT statement
pIns.setInt(1, 100);
pIns.setString(2, "N");
pIns.setString(3, "Fiberifics");
pIns.setString(4, "123 any street");

// Execute the INSERT statement
pIns.executeUpdate();

// Data for second INSERT statement
pIns.setInt(1, 101);
pIns.setString(2, "N");
pIns.setString(3, "Natural Foods Co.");
pIns.setString(4, "5150 Johnson Rd");

// Execute the INSERT statement
pIns.executeUpdate();

// Commit the inserts
conn.commit();

// Done with INSERTs, so close the prepared statement
pIns.close();

// Report any SQLWarnings on the connection. 
reportSQLWarnings(conn.getWarnings());

// Execute the prepared SELECT statement
ResultSet rs = pSel.executeQuery();

System.out.println("Fetching result set...");
while (rs.next()) {
    System.out.println("\n Customer number: " + rs.getInt(1));
    System.out.println(" Region: " + rs.getString(2));
    System.out.println(" Name: " + rs.getString(3));
    System.out.println(" Address: " + rs.getString(4));
}

// Close the result set.
rs.close();

// Commit the select - yes selects must be committed too
conn.commit();

// Close the select statement - we are done with it
pSel.close();

例2-8 複数の接続のための準備された文

この例では、3つの接続に対して、パラメータを使用した同一のINSERT文を3つ準備します。接続conn1の最初の準備済INSERTは、TimesTen内部の準備済文キャッシュ内でconn2およびconn3接続と共有され、pIns2およびpIns3の準備操作を加速します。

Connection conn1 = null;
Connection conn2 = null;
Connection conn3 = null;
.....
PreparedStatement pIns1 = conn1.prepareStatement
                  ("insert into t1 values (?,?)");

PreparedStatement pIns2 = conn2.prepareStatement
                  ("insert into t1 values (?,?)");

PreparedStatement pIns3 = conn3.prepareStatement
                  ("insert into t1 values (?,?)");

ノート:

結合順序、索引、ロックなど、すべてのオプティマイザ・ヒントは、TimesTenの内部準備済文キャッシュで共有される文と一致している必要があります。また、準備された文が一時表を参照する場合、この文は1つの接続内でのみ共有されます。

出力および入力/出力パラメータの使用

「SQL文の準備および入力パラメータの設定」では、文の準備の方法およびPreparedStatementメソッドを使用した入力パラメータの設定について説明しています。TimesTenでは、PreparedStatementのかわりにjava.sql.CallableStatementを使用する、次の出力および入力/出力パラメータもサポートしています。

  1. メソッドregisterOutParameter()を使用して、出力パラメータまたは入力/出力パラメータを登録し、パラメータの位置(文内の位置)およびデータ型を指定します。

    これは、CallableStatementインタフェースで指定されている標準のメソッドです。

    void registerOutParameter(int parameterIndex, int sqlType, int scale)
    

    ただし、CHARVARCHARNCHARNVARCHARBINARYまたはVARBINARYデータに対してこの標準バージョンを使用すると、TimesTenでは、指定可能な最大値を保持するために必要なメモリーを割り当てます。これは、ほとんどの場合で無駄になります。

    そのかわりに、最大データ長を指定できるregisterOutParameter()シグネチャが含まれるTimesTenの拡張インタフェースTimesTenCallableStatementを使用します。CHARVARCHARNCHARおよびNVARCHARについては、長さの単位は文字数になります。BINARYおよびVARBINARYについてはバイトになります。

    void registerOutParameter(int paramIndex,
                              int sqlType,
                              int ignore, //This parameter is ignored by TimesTen.
                              int maxLength)
    
  2. 適切なCallableStatementメソッドsetXXX()を使用し(XXXはデータ型を示します)、入力/出力パラメータの入力値を設定します。パラメータの位置およびデータの値を指定します。

  3. 適切なCallableStatementメソッドgetXXX()を使用して、出力パラメータまたは入力/出力パラメータの出力値を取得し、パラメータの位置を指定します。


重要:

出力パラメータを処理する前にSQL警告を確認します。警告イベント中には、出力パラメータは定義されません。エラーおよび警告に関する一般的な情報は、「エラー処理」を参照してください。


ノート:

TimesTenの場合:
  • 名前を使用してパラメータをCallableStatementオブジェクトに渡すことはできません。位置でパラメータを設定する必要があります。SQLのエスケープ構文は使用できません。

  • 名前によってパラメータを指定するregisterOutParameter()シグネチャはサポートされていません。位置によってパラメータを指定する必要があります。

  • SQL構造型はサポートされていません。


例2-9 コール可能な文での出力パラメータの使用

この例は、コール可能な文での出力パラメータの使用方法を示します。TimesTenCallableStatementインスタンスで、PL/SQLブロックは、新しい給与を計算し、整数で返すファンクションRAISE_SALARYをコールします。Connectionインスタンスをconnとします。(PL/SQLに関する情報は、『Oracle TimesTen In-Memory Database PL/SQL開発者ガイド』を参照してください。)

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Types;
import com.timesten.jdbc.TimesTenCallableStatement;
...
// Prepare to call a PL/SQL stored procedure RAISE_SALARY
CallableStatement cstmt = conn.prepareCall
                          ("BEGIN :newSalary := RAISE_SALARY(:name, :inc); end;");
      
// Declare that the first param (newSalary) is a return (output) value of type int
cstmt.registerOutParameter(1, Types.INTEGER);
 
// Raise Leslie's salary by $2000 (she wanted $3000 but we held firm)
cstmt.setString(2, "LESLIE"); // name argument (type String) is the second param
cstmt.setInt(3, 2000); // raise argument (type int) is the third param
 
// Do the raise
cstmt.execute();

// Check warnings. If there are warnings, output parameter values are undefined.
SQLWarning wn;
boolean warningFlag = false;
if ((wn = cstmt.getWarnings() ) != null) {
   do {
        warningFlag = true;
        System.out.println(wn);
        wn = wn.getNextWarning();
   } while(wn != null);
}      
      
// Get the new salary back
if (!warningFlag) {
   int new_salary = cstmt.getInt(1);
   System.out.println("The new salary is: " + new_salary);
}

// Close the statement and connection
cstmt.close();
conn.close();
...

SQL文で重複パラメータをバインドする

TimesTenでは、1つのSQL文に同じパラメータ名が複数出てきた場合は異なるパラメータとみなされます。(これは、Oracle Databaseによる重複パラメータのバインディングのサポートに準拠しています。)


ノート:

  • この説明は、PL/SQL経由などではなく、ODBCから直接発行されるSQL文にのみ当てはまります。

  • 重複したパラメータをバインディングする「TimesTenモード」、およびDuplicateBindMode接続属性は非推奨となっています。


次の問合せについて考えてみます。

SELECT * FROM employees
  WHERE employee_id < :a AND manager_id > :a AND salary < :b;

パラメータ位置番号を割り当てるとき、名前の重複は考慮せずに各パラメータの出現に番号が割り当てられます。アプリケーションでは、最低でも、各パラメータ名の最初の出現に値がバインドされます。そのパラメータ名が次回出現した場合、アプリケーションでは次のいずれかが実行されます。

  • その出現に対して別の値をバインドします。

  • そのパラメータの出現をバインドしないままにします。この場合は、最初の出現と同じ値をとります。

どちらの場合でも、それぞれの出現は、異なるパラメータ位置番号を持っています。

前述のSQL文で、aの2度目の出現に対して別の値を使用するには、次のようにします。

pstmt.setXXX(1, ...); /* first occurrence of :a */
pstmt.setXXX(2, ...); /* second occurrence of :a */
pstmt.setXXX(3, ...); /* occurrence of :b */

両方のaの出現に対して同じ値を使用するには、次のようにします。

pstmt.setXXX(1, ...); /* both occurrences of :a */
pstmt.setXXX(3, ...); /* occurrence of :b */

いずれの場合も、パラメータbは位置3にあるとみなされます。

PL/SQL文で重複パラメータをバインドする

前述の説明は、独自のセマンティクスがあるPL/SQLには該当しません。PL/SQLでは、一意の各パラメータ名に値をバインドします。たとえば、次のブロックを実行するアプリケーションは、:aに対応する1つのパラメータのみをバインドします。

DECLARE
   x NUMBER;
   y NUMBER;
BEGIN
   x:=:a;
   y:=:a;
END;

次のブロックを実行するアプリケーションでも、1つのパラメータのみをバインドします。

BEGIN
   INSERT INTO tab1 VALUES(:a, :a);
END

これは、次のCALL文でも同様です。

...CALL proc(:a, :a)...

次のブロックを実行するアプリケーションは、2つのパラメータ(パラメータ#1に:a、パラメータ#2に:b)をバインドします。各INSERT文の2番目のパラメータは、次のように、最初のINSERT文の最初のパラメータと同じ値を使用します。

BEGIN
   INSERT INTO tab1 VALUES(:a, :a);
   INSERT INTO tab1 VALUES(:b, :a);
END

連想配列のバインド

TimesTen JDBCでは、TimesTen PL/SQLへのINOUTまたはIN OUTバインド・パラメータである、以前の索引付き表またはPL/SQL表と呼ばれていた連想配列バインドをサポートしています。連想配列では、JDBCアプリケーションとデータベース間で効率的にデータの配列を渡すことを可能にします。

連想配列とは、キーと値のペアのセットです。TimesTenの連想配列バインド(PL/SQL内のみに連想配列の使用は限定されません)では、キーまたは索引は整数(BINARY_INTEGERまたはPLS_INTEGER)である必要があります。値は、同じデータ型の単純なスカラー値である必要があります。たとえば、部署番号ごとに索引付された部署のマネージャの配列を作成できます。索引は、作成された順序ではなく、ソートされた順序で格納されます。

次の例のように、PL/SQLで連想配列型を宣言した後、連想配列を宣言します(INDEX BYに注意してください)。

declare
   TYPE VARCHARARRTYP IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
   x VARCHARARRTYP;
   ...

Oracle TimesTen In-Memory Database PL/SQL開発者ガイドのアプリケーションからの連想配列の使用に関する説明も参照してください。

Javaで連想配列をバインドする場合、配列の型とできるだけ近いJavaの型を使用すると最適なパフォーマンスが得られます。ただし、TimesTenでは、次のいくつかの単純な入力時の変換をサポートしています。

  • 文字列は整数または浮動小数点に変換できます。

  • 文字列がTimesTenのDATE(YYYY-MM-DD HH:MI:SS)の書式に従っている場合、文字列をDATEデータに変換できます。


ノート:

TimesTenには次の制限があることに注意してください。
  • 連想配列のバインドでは、LOB、REF CURSOR、TIMESTAMPROWIDの型はサポートされていません。

  • パススルー文では連想配列のバインドはサポートされていません。

  • TimesTenのJDBCでは、一般的な配列のバルク・バインドはサポートされていません。VARRAYおよびネストされた表は、バインド・パラメータとしてサポートされていません。

  • 連想配列パラメータは、JDBCのバッチの実行ではサポートされていません(「バッチ実行にパラメータの配列を使用」を参照してください)。


TimesTenには、TimesTenPreparedStatementTimesTenCallableStatementのインタフェースを介して連想配列のバインドをサポートする、次で説明する拡張が用意されています。ここで説明するメソッドの詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

TimesTenでは、PL/SQLのINまたはIN OUTパラメータである連想配列で入力連想配列を設定するために、(INパラメータ用に)TimesTenPreparedStatementインタフェースで、また(IN OUTパラメータ用に)TimesTenCallableStatementインタフェースで、setPlsqlIndexTable()メソッドを用意しています。

  • void setPlsqlIndexTable(int paramIndex, java.lang.Object arrayData, int maxLen, int curLen, int elemSqlType, int elemMaxLen)

    次のように指定します。

    • paramIndex: (1で開始する)PL/SQL文内のパラメータの位置

    • arrayData: バインドする値の配列(これはint[]などプリミティブ型の配列またはBigDecimal[]などオブジェクト型の配列が許可されます)

    • maxLen: 連想配列内の要素の最大数(TimesTenでは、curLenと同じにする必要があります)

    • curLen: 連想配列内に現在ある要素の実際の数(TimesTenではmaxLenと同じである必要があります)

    • elemSqlType: java.sql.Typesと一致する連想配列の要素の型(Types.DOUBLEなど)

    • elemMaxLen: CHARVARCHARBINARYまたはVARBINARYの連想配列で、各要素の最大長(CHARまたはVARCHARの連想配列では文字列、BINARYまたはVARBINARYの連想配列ではバイトです)

    次に例を示します(TimesTenPreparedStatementインスタンスpstmtを仮定)。

    int maxLen = 3;
    int curLen = 3;
    // Numeric field can be set with int, float, double types.
    // elemMaxLen is set to 0 for numeric types and is ignored.
    // elemMaxLen is specified for VARCHAR types.
    pstmt.setPlsqlIndexTable
          (1, new int[]{4, 5, 6}, maxLen, curLen, Types.NUMERIC, 0);
    pstmt.setPlsqlIndexTable
          (2, new String[]{"Batch1234567890", "2", "3"}, maxLen, curLen,
           Types.VARCHAR, 15);
    pstmt.execute();
    

ノート:

  • elemMaxLenパラメータは、CHARVARCHARBINARYまたはVARBINARY以外の型では無視されます。それらのすべての型では、値に0を使用すると、バインドされているデータの実際の長さに基づいて各要素の最大長を設定するようドライバに指示できます。elemMaxLenが正の値に設定され、実際のデータ長がelemMaxLenより大きい場合、データは常にelemMaxLenの長さに切り捨てられます。

  • curLenが連想配列内の実際の要素数より小さい場合、curLenの要素のみがバインドされます。


TimesTenでは、PL/SQLのOUTまたはIN OUTパラメータである連想配列用に、出力連想配列を登録するregisterIndexTableOutParameter()と出力連想配列を取得するgetPlsqlIndexTable()の2つのメソッドをTimesTenCallableStatementインタフェースに用意しています。getPlsqlIndexTable()には、連想配列の要素がSQL型であると仮定しJDBCのデフォルトのJavaオブジェクト型を使用するものと、型を指定する2つのシグネチャがあります。

  • void registerIndexTableOutParameter(int paramIndex, int maxLen, int elemSqlType, int elemMaxLen)

    次のように指定します。

    • paramIndex: (1で開始する)PL/SQL文内のパラメータの位置

    • maxLen: 連想配列に含めることが可能な要素の最大数

    • elemSqlType: java.sql.Typesと一致する連想配列の要素の型(Types.DOUBLEなど)

    • elemMaxLen: CHARVARCHARBINARYまたはVARBINARYの連想配列で、各要素の最大長(CHARまたはVARCHARの連想配列では文字列、BINARYまたはVARBINARYの連想配列ではバイトです)


    ノート:

    elemMaxLenの値が0以下の場合、データ型の最大長が使用されます。

  • java.lang.Object getPlsqlIndexTable(int paramIndex)

    このメソッド・シグネチャでは、返された連想配列の型が、取得したSQL型のデータのJDBCでのデフォルトのマッピングになります。(1で開始する)PL/SQL文内のパラメータの位置を指定します。デフォルト・マッピングについては、表2-4を参照してください。

  • java.lang.Object getPlsqlIndexTable(int paramIndex, java.lang.Class primitiveType)

    このメソッド・シグネチャでは、パラメータの位置の指定に加え、java.sql.Typesと一致する返される連想配列の希望の型を指定します(Types.DOUBLEなど)。これはプリミティブ型である必要があります。


ノート:

連想配列バインドのためのTimesTenの拡張については、java.sql.PreparedStatementCallableStatementではなくTimesTenPreparedStatementおよびTimesTenCallableStatementのインスタンスを使用する必要があります。

表2-4 連想配列要素のJDBCのデフォルト・マッピング

戻り値の型 SQLの型

Integer[]

TINYINTSMALLINTTT_INTEGER

Long[]

BIGINT

BigDecimal[]

NUMBER

Float[]

BINARY_FLOAT

Double[]

BINARY_DOUBLE

String[]

CHARVARCHARNCHARNVARCHAR

Timestamp[]

DATE


次のコード部分では、IN OUTパラメータの内容を設定、登録および取得する方法を示しています(connは接続、cstmtTimesTenCallableStatementインスタンスを想定しています)。

int maxLen = 3;
int curLen = 3;
anonBlock = "begin AssocArrayEx_inoutproc(:o1); end;";
cstmt = (TimesTenCallableStatement) conn.prepareCall(anonBlock); 
cstmt.setPlsqlIndexTable
     (1, new Integer[] {1,2,3}, maxLen, curLen, Types.NUMERIC, 0);
cstmt.registerIndexTableOutParameter(1, maxLen, Types.NUMERIC, 0);
cstmt.execute();
 
int[]  ret = (int [])cstmt.getPlsqlIndexTable(1, Integer.TYPE);
cstmt.execute();

例2-10 連想配列のバインド

連想配列のバインドのメカニズムを示すより完全な例を次に示します。

    TimesTenCallableStatement cstmt = null;
    try {
      // Prepare procedure with associative array in parameter
      cstmt = (TimesTenCallableStatement) 
               conn.prepareCall("begin AssociativeArray_proc(:name, :inc); end;");
      
      // Set up input array and length
      String[] name = {"George", "John", "Thomas", "James", "Bill"};
      Integer[] salaryInc = {10000, null, 5000, 8000, 9007};
      int currentLen = name.length;
      int maxLen = currentLen;
 
      
      // Use elemMaxLen for variable length data types such as 
      // Types.VARCHAR, Types.CHAR.
      int elemMaxLen = 32; 
      
      // set input parameter, name as a VARCHAR
      cstmt.setPlsqlIndexTable 
            (1, name, maxLen, currentLen, Types.VARCHAR, elemMaxLen);
      // set input parameter, salaryInc as a number
      cstmt.setPlsqlIndexTable 
            (2, salaryInc, maxLen, currentLen, Types.NUMERIC, 0);

REF CURSORの使用

REF CURSORはPL/SQLの概念で、PL/SQLとアプリケーション間で受け渡しされるSQL結果セット上のカーソルに対するハンドルです。TimesTenでは、PL/SQL内でカーソルをオープンできるため、そのREF CURSORをアプリケーションに渡して結果セットを処理することができます。

TimesTenでは、標準のREFカーソルおよびTimesTen REF CURSORがサポートされています。(TimesTen固有のサポートは、標準サポートの前に実装されました。)

アプリケーションは、次のように、REF CURSOR OUTパラメータを受け取ることができます。

  1. CallableStatementメソッドregisterOutParameter()を使用して、REF CURSOR OUTパラメータをjava.sqlTypes.REF_CURSOR型として(標準のREF CURSORの場合)またはTimesTenTypes.CURSOR型として(TimesTen REF CURSORの場合)登録します。registerOutParameter()コールで、REF CURSORのパラメータ位置(文内の位置)を指定します。

  2. CallableStatementメソッドgetObject() (標準REF CURSORの場合)またはTimesTenCallableStatementメソッドgetCursor() (TimesTenREF CURSORの場合)を使用してREF CURSORを取得し、戻り値をResultSetとしてキャストします。REF CURSORのパラメータ位置を指定します。

TimesTen JDBC APIの詳細は、Oracle TimesTen In-Memory Database JDBC拡張Java APIリファレンスを参照してください。REF CURSORの詳細は、『Oracle TimesTen In-Memory Database PL/SQL開発者ガイド』のPL/SQL REF CURSORに関する説明を参照してください。


重要:

PL/SQLとアプリケーションの間でREF CURSORを渡す場合、TimesTenでは、PL/SQLからアプリケーションへのOUTREF CURSORのみがサポートされます。文は、1つのREF CURSORのみを返すことができます。

次の例でこれを説明します。

例2-11 REF CURSORの使用

この例では、コール可能な文でのTimesTen REF CURSORの使用方法を示し、次に標準のREF CURSORの使用方法を示しています。

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import com.timesten.jdbc.TimesTenCallableStatement;
import com.timesten.jdbc.TimesTenTypes;
...
Connection conn = null;
CallableStatement cstmt = null;
ResultSet cursor;
...
// Use a PL/SQL block to open the cursor.
cstmt = conn.prepareCall
             (" begin open :x for select tblname,tblowner from tables; end;");
cstmt.registerOutParameter(1, TimesTenTypes.CURSOR);
cstmt.execute();
cursor = ((TimesTenCallableStatement)cstmt).getCursor(1);

// Use the cursor as you would any other ResultSet object.
while(cursor.next()){
  System.out.println(cursor.getString(1));
}

// Close the cursor, statement, and connection.
cursor.close();
cstmt.close();
conn.close();
...

標準REF CURSORの場合:

...
Connection conn = null;
CallableStatement cstmt = null;
ResultSet rs;
...
cstmt = conn.prepareCall
             (" begin open :x for select tblname,tblowner from tables; end;");
cstmt.registerOutParameter(1, Types.REF_CURSOR); 
cstmt.execute(); 
rs = cstmt.getObject(1, ResultSet.class);
while(rs.next()){
  System.out.println(rs.getString(1));
}

// Close the result set, statement, and connection.
rs.close();
cstmt.close();
conn.close();
...

ノート:

ループ内に様々なパラメータ値があるコール可能な文を評価する場合、ループの終了時には毎回カーソルをクローズする必要があります。文を準備した後にループにパラメータを設定し、文を実行し、カーソルを処理し、カーソルをクローズするのが標準的な使用法です。

DML RETURNING(RETURNING INTO句)の使用

DML RETURNINGと呼ばれるRETURNING INTO句をINSERTUPDATEまたはDELETE文で使用すると、処理の影響を受けた行の特定の項目を返すことができます。これにより、たとえば処理によって影響を受けたものを確認する場合などで、続くSELECT文および個々のラウンド・トリップが不要になります。

TimesTenでは、DML RETURNINGは、単一行の操作から項目を戻すのみです。この句では、項目を出力パラメータのリストに返します。

TimesTenPreparedStatement(標準PreparedStatementインタフェースの拡張)は、DML RETURNINGをサポートします。TimesTenPreparedStatementメソッドregisterReturnParameter()を使用して、戻りパラメータを登録します。

void registerReturnParameter(int paramIndex, int sqlType)

「出力および入力/出力パラメータの使用」で説明したregisterOutParameter()メソッドと同様に、このメソッドには、CHARVARCHARNCHARNVARCHARBINARYまたはVARBINARYのデータにオプションで最大サイズを指定できるシグネチャがあります。これにより、TimesTenが非効率に設定可能な最大のメモリー値を割り当ててしまう可能性が回避されます。CHARVARCHARNCHARおよびNVARCHARのサイズ単位は、文字数です。BINARYおよびVARBINARYについてはバイトになります。

void registerReturnParameter(int paramIndex, int sqlType, int maxSize)

TimesTenPreparedStatementメソッドgetReturnResultSet()を使用して戻りパラメータを取得し、ResultSetインスタンスを返します。

TimesTen JDBCでRETURNING INTOを使用する場合は、次の制限に注意してください。

  • getReturnResultSet()メソッドは2回以上実行しないでください。実行すると、動作は不確定です。

  • getReturnResultSet()が返す結果セットは、ResultSetMetaDataをサポートしていません。

  • getReturnResultSet()が返す結果セットは、getCharacterStream()などのストリーミング・メソッドをサポートしていません。

  • DML RETURNINGをサポートするバッチはありません。

ここで説明するTimesTenのJDBCクラス、インタフェース、メソッドの詳細は、Oracle TimesTen In-Memory Database JDBC拡張Java APIリファレンスを参照してください。

Oracle TimesTen In-Memory Database SQLリファレンスのINSERT、UPDATEおよびDELETEに関する説明内には、TimesTenのRETURNING INTO句のSQL構文および制限についての説明があります。

DML RETURNINGに関する一般的な情報は、『Oracle Database PL/SQL言語リファレンス』のRETURNING INTO句に関する説明を参照してください。


重要:

TimesTenの準備済の文の実行後は、SQL警告を確認してください。警告イベント中には、出力パラメータは定義されません。エラーおよび警告に関する一般的な情報は、「エラー処理」を参照してください。

例2-12 DML RETURNING

この例では、TimesTenPreparedStatementインスタンスでDML RETURNINGを使用する方法を示しています。挿入された行の名前および経過時間を返します。

      import java.sql.ResultSet;
      import java.sql.SQLException;
      import java.sql.SQLWarning;
      import java.sql.Types;
      import com.timesten.jdbc.TimesTenPreparedStatement;
 
      Connection conn = null;
      ...
 
      // Insert into a table and return results
      TimesTenPreparedStatement pstmt =
        (TimesTenPreparedStatement)conn.prepareStatement
        ("insert into tab1 values(?,?) returning name, age into ?,?");
 
      // Populate table
      pstmt.setString(1,"John Doe");
      pstmt.setInt(2, 65);
 
      /* register returned parameter
       * in this case the maximum size of name is 100 chars
       */
      pstmt.registerReturnParameter(3, Types.VARCHAR, 100);
      pstmt.registerReturnParameter(4, Types.INTEGER);
 
      // process the DML returning statement
      int count = pstmt.executeUpdate();
 
      /* Check warnings; if there are warnings, values of DML RETURNING INTO
         parameters are undefined. */
      SQLWarning wn;
      boolean warningFlag = false;
      if ((wn = pstmt.getWarnings() ) != null) {
        do {
          warningFlag = true;
          System.out.println(wn);
          wn = wn.getNextWarning();
        } while(wn != null);
      }
 
      if (!warningFlag) {
        if (count>0)
        {
          ResultSet rset = pstmt.getReturnResultSet(); //rset not null, not empty
          while(rset.next())
          {
            String name = rset.getString(1);
            int age = rset.getInt(2);
            System.out.println("Name " + name + " age " + age);
          }
        }
      }

ROWIDの使用

各行には、rowidと呼ばれる行の一意の識別子があります。アプリケーションは、行のROWIDをROWID擬似列から取得できます。ROWID値はバイナリまたは文字形式で表現され、12バイトのバイナリ形式および18バイトの文字形式で表されます。

TimesTenでは、java.sql.RowIdインタフェースとTypes.ROWID型をサポートしています。

次のResultSetメソッドを使用して、ROWIDを取得できます。

  • RowId getRowId(int columnIndex)

  • RowId getRowId(String columnLabel)

次のPreparedStatementメソッドを使用して、ROWIDを設定できます。

  • setRowId(int parameterIndex, RowId x)

アプリケーションでは、SQL文のWHERE句などで、一重引用符で囲んだCHAR定数としてリテラルのROWID値を指定できます。

使用法およびライフサイクルを含むrowidおよびROWIDデータ型の詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のROWIDデータ型およびROWID擬似列に関する説明を参照してください。


ノート:

TimesTenでは、PL/SQL型UROWIDをサポートしていません。

LOBの作業

TimesTen Classicでは、LOB(ラージ・オブジェクト)をサポートしています(具体的には、CLOB(Character LOB)、NCLOB(National Character LOB)およびBLOB(Binary LOB))。

この項では、LOBの概要およびLOBのJDBCでの使用について、次の内容で説明します。

次の情報も参照できます。

  • TimesTenにおけるLOBの詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のLOBのデータ型に関する説明を参照してください。

  • LOBを使用したプログラミングの全般的情報については、Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド(TimesTenでの機能には限定されません)を参照してください。

LOBの概要

LOBとは、ラージ・バイナリ・オブジェクト(BLOB)または文字オブジェクト(CLOBまたはNCLOB)です。TimesTenでは、BLOBは最大16 MBで、CLOBまたはNCLOBは最大4 MBになります。記載がないかぎり、基本的にTimesTenのLOBはOracle Databaseでの場合と同様に機能します。(「TimesTenのLOBとOracle DatabaseのLOBの違い」を参照してください)。

LOBは永続する場合も一時的である場合もあります。永続LOBは、データベースのLOB列に存在します。一時LOBはアプリケーション内のみに存在します。一時LOBは、TimesTenによって黙示で作成される場合もあります。たとえば、SELECT文によって追加の文字列と連結されたLOBが選択される場合、連結データを含むようTimesTenでは一時LOBを作成します。

JDBCでのLOB

JDBCでは、LOBオブジェクト(BlobClobまたはNClobインスタンス)には、データ自体ではなくLOBデータへの論理ポインタがLOBオブジェクトに含まれることを意味するSQL LOBロケータ(BLOBCLOBまたはNCLOB)を使用して実装されます。


重要:

  • トランザクションが終了すると、TimesTenではLOBオブジェクトは無効になるので、自動コミットを有効にして使用することはできません。LOBが無効になったことを示すエラーが通知されます。

  • APIを介したLOBロケータを使用するLOB操作では、TimesTenの一時領域が使用されます。このような操作が頻繁に行われる場合には、TimesTenの一時データ領域サイズの拡大が必要になることがあります。詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のTempSizeに関する説明を参照してください。


アプリケーションは、JDBC APIを使用して、アプリケーション内で使用するために一時LOBを明示的にインスタンス化でき、処理が終了したらLOBを解放できます。一時LOBは、TimesTenの一時データ領域に保存されます。

永続LOBを更新する場合、トランザクションで、LOBを含む行の排他ロックを取得する必要があります。これは、LOBをSELECT ... FOR UPDATE文で選択することによって実現できます。これによって、ロケータが書込み可能になります。単純なSELECT文では、ロケータは読取り専用となります。読取り専用ロケータと書込み可能ロケータは次のように動作します。

  • 読取り専用ロケータは、存続期間中、LOBを選択したときのコンテンツのみを参照する、一貫して読み取りを行うものとなります。これには、LOBが選択される前、同じトランザクションでLOBに対して実行したすべてのコミットされていない更新が含まれることに注意してください。

  • 書込み可能ロケータは、ロケータを介した書込みのたびに、データベースの最新データで更新されます。したがって、書込みはLOBの最新データに対して行われます(これには、他のロケータを介して実行された更新も含みます)。

次に、同じLOBに対する2つの書込み可能ロケータの詳しい動作例を示します。

  1. LOB列にXYが含まれます。

  2. 更新するために、ロケータL1を選択します。

  3. 更新するために、ロケータL2を選択します。

  4. オフセット1でL1を介し、Zを書き込みます。

  5. ロケータL1を介して読み取ります。これによって、ZYが返されます。

  6. ロケータL2を介して読み取ります。L2は書込みに使用されるまで、一貫して読み取りを行うため、これによってXYが返されます。

  7. オフセット2でL2を介し、Wを書き込みます。

  8. ロケータL2を介して読み取ります。これによって、ZWが返されます。前のステップの書込みの前に、ロケータは最新のデータ(ZY)で上書きされました。

TimesTenのLOBとOracle DatabaseのLOBの違い

次のことに注意してください。

  • TimesTenのLOB実装とOracle Database実装の主な違いは、TimesTenでは、トランザクションの終了後、LOBオブジェクトが無効になるということです。明示的か暗黙的かにかかわらず、コミットまたはロールバック後、すべてのLOBオブジェクトは無効になります。これには、あらゆる自動コミット後(自動コミットの有効化によりLOBの使用が不可能になります)、またはDDL文後が含まれます。

  • TimesTenでは、BFILE、SecureFile、LOBの配列の読取りおよび書込みまたはLOBのコールバック・ファンクションをサポートしていません。

  • TimesTenでは、LOBの連想配列のバインドはサポートしていません。

  • TimesTenでは、LOBのバッチ処理はサポートしていません。

  • BLOBに関して、TimesTenの16進リテラルの使用法に違いがあります。詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』定数のHexadecimalLiteralに関する説明を参照してください。

LOBファクトリ・メソッド

TimesTenでは、標準のConnectionメソッドのcreateBlob()createClob()およびcreateNClob()をサポートしています。

詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。


重要:

TimesTenでは、LOBオブジェクトを作成すると、まだ進行中でない場合は、データベース・トランザクションが作成されます。コミットまたはロールバックを実行し、トランザクションをクローズする必要があります。

LOBのgetterメソッドとsetterメソッド

LOBには、他のデータ型の場合と同様に、標準のjava.sql.ResultSetPreparedStatementおよびCallableStatementインタフェースで定義するgetterメソッドおよびsetterメソッドを介してアクセスできます。次の適切なgetXXX()メソッドを使用しLOBの結果または出力パラメータを取得するか、setXXX()メソッドを使用しLOB入力パラメータをバインドします。

  • ResultSet getterメソッド: 列名または列索引のいずれかに基づいてLOBに取得を指定する、getBlob()メソッド、getClob()メソッドおよびgetNClob()メソッドがあります。

    BlobClobまたはNClobオブジェクトを取得するgetObject()も使用できます。

  • PreparedStatement setterメソッド: BlobClobまたはNClobインスタンスとパラメータ索引を入力し、入力パラメータをバインドする、setBlob()メソッド、setClob()メソッドおよびsetNClob()メソッドがあります。

    BlobClobまたはNClob入力パラメータをバインドするsetObject()も使用できます。

    また、Blobインスタンスのかわりに、InputStreamインスタンスまたはInputStreamインスタンスと長さを指定するsetBlob()メソッドもあります。

    setClob()およびsetNClob()メソッドでは、ClobまたはNClobインスタンスのかわりに、ReaderインスタンスまたはReaderインスタンスと長さを指定します。

  • CallableStatement getterメソッド: パラメータ名またはパラメータ索引のいずれかに基づいてLOB出力パラメータを取得するgetBlob()メソッド、getClob()メソッドおよびgetNClob()メソッドがあります。

    BlobClobまたはNClob出力パラメータを取得するgetObject()も使用できます。

    また、CallableStatementオブジェクトから出力パラメータを登録する必要もあります。registerOutParameter()メソッドでは、パラメータ索引とともにTypes.BLOBTypes.CLOBまたはTypes.NCLOBのSQL型を取ります。

  • CallableStatement setterメソッド: これは、PreparedStatement setterメソッドと同一です(継承されます)。

詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

TimesTenのLOBインタフェース・メソッド

Blobインスタンスをcom.timesten.jdbc.TimesTenBlobに、Clobインスタンスをcom.timesten.jdbc.TimesTenClobに、NClobインスタンスをcom.timesten.jdbc.TimesTenNClobにキャストできます。これらのインタフェースでは、java.sql.BlobClobおよびNClobインタフェースで指定するメソッドをサポートしています。

Blobの機能の概要は、次のとおりです。

  • TimesTenの拡張であるisPassthrough()メソッドは、BLOBがOracle DatabaseからのパススルーLOBであるかどうかを示します。

  • アプリケーションが処理を完了したら、Blobリソースを解放します。

  • BLOB値をバイナリ・ストリームとして取得します。一部または全部を取得するメソッドがあります。

  • バイト配列として、BLOB値の全部または一部を取得します。

  • BLOBのバイト数を戻します。

  • BLOBへのバイナリ・データの書込み(指定した位置から開始)に使用するストリームを取得します。これは既存のデータを上書きします。

  • BLOBに書き込むバイトの配列を指定し(指定した位置から開始)、書き込んだバイト数を戻します。これは既存のデータを上書きします。配列の全部または一部を書き込むメソッドがあります。

  • 指定した長さにBLOBを切り捨てます。

ClobおよびNClobの機能の概要は、次のとおりです。

  • TimesTenの拡張であるisPassthrough()メソッドは、CLOBまたはNCLOBがOracle DatabaseからのパススルーLOBであるかどうかを示します。

  • アプリケーションが処理を終了したら、ClobまたはNClobリソースを解放します。

  • CLOBまたはNCLOBをASCIIストリームとして取得します。

  • CLOBまたはNCLOBをjava.io.Readerオブジェクト(または文字のストリーム)として取得します。一部または全部を取得するメソッドがあります。

  • CLOBまたはNCLOB内の指定したサブストリングのコピーを、指定の最大長まで(指定した位置から開始して)取得します。

  • CLOBまたはNCLOBの文字数を戻します。

  • CLOBまたはNCLOBへのASCII文字の書込み(指定した位置から開始)に使用するストリームを取得します。これは既存のデータを上書きします。

  • CLOBまたはNCLOBに書き込む(指定した位置から開始)、Java String値を指定します。これは既存のデータを上書きします。String値の全部または一部を書き込むメソッドがあります。

  • 指定した長さにCLOBまたはNCLOBを切り捨てます。


ノート:

  • LOBにデータを書き込むメソッドの場合、書き込まれるデータよりも少ない領域しか指定した位置以降にLOBにない場合を除き、LOBのサイズは変わりません。その場合、データが収まるようLOBのサイズが拡張されます。

  • LOBの書込みを指定した位置の値が、LOBの長さに1を足したものより大きい場合の動作は定義されていません。

  • InputStreamまたはReaderオブジェクト内のデータ量にかかわらず、メソッド・コールで使用されるバッファ長が0のとき、InputStreamまたはReaderオブジェクトのread()メソッドでは0(ゼロ)が返されます。したがって、SQL EMPTY_CLOB()ファンクションを使用して入力した場合のように、CLOBの長さが0のとき、次のような使用は問題になることがあります。

    java.io.Reader r = myclob.getCharacterStream();
    char[] buf = new char[myclob.length()]; //buf for r.read() call
    

    通常、read()をコールして、ストリームの最後に達すると-1が返されます。ただし、前の例では-1が返されることはありません。InputStreamを返すBLOB getBinaryStream()メソッド、InputStreamを返すCLOB getAsciiStream()メソッド、Readerを返すCLOB getCharacterStream()メソッドによって返されるストリームを使用する場合は、これに注意してください。


詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

LOBのプリフェッチ

クライアント/サーバー接続でのサーバーへのラウンドトリップを減らすために、データベースからLOBをフェッチするとき、デフォルトでLOBのプリフェッチが有効になっています。プリフェッチのデフォルト・サイズは、BLOBの場合は4,000バイトで、CLOBまたはNCLOBの場合は4,000文字です。

TimesTenConnectionプロパティCONNECTION_PROPERTY_DEFAULT_LOB_PREFETCH_SIZEを使用すると、デフォルト値とは異なる値を接続のすべての文に適用するよう設定できます。値-1を使用すると、その接続ではデフォルトでLOBのプリフェッチが無効になり、0(ゼロ)を使用するとデフォルトでメタデータのみのLOBのプリフェッチが有効になり、0より大きい任意の値を指定すると、フェッチ操作時にLOBロケータとともに、デフォルトでBLOBのバイト数またはCLOBとNCLOBの文字数がプリフェッチされるよう指定できます。

文レベルで次のTimesTenStatementメソッドを使用すると、接続のプリフェッチ・サイズの操作とデフォルト値の上書きが可能になります。

  • setLobPrefetchSize(int): 文の新しいLOBプリフェッチ値を指定します。

  • int getLobPrefetchSize(): 文に適用されている現在のLOBプリフェッチ値を戻します(該当する文自体に設定した値または接続のデフォルト値)。

詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

パススルーLOB

パススルーLOB(TimesTenを介してアクセスするOracle Database内のLOB)は、TimesTenのLOBとして公開され、TimesTenのLOBがサポートされているのとほぼ同様にTimesTenでサポートされていますが、次のことにノートする必要があります。

  • 「TimesTenのLOBインタフェース・メソッド」のとおり、TimesTenBlobTimesTenClobおよびTimesTenNClobインタフェースでは、そのLOBがパススルーLOBであるかを示す次のメソッドを規定しています。

    boolean isPassthrough()

  • TimesTenのLOBのサイズ制限は、パススルーによるOracle DatabaseのLOBの保存には適用されません。

  • TimesTenのローカルのLOBと同様に、パススルーLOBオブジェクトはトランザクションが終了すると無効になります。

詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

データベースに対する変更のコミットまたはロールバック

この項では、自動コミットおよび手動コミット、またはロールバックについて説明します(JDBC ConnectionオブジェクトをmyconnStatementオブジェクトをmystmtと仮定しています)。


ノート:

接続上のすべてのオープン・カーソルは、TimesTenでのトランザクションのコミットまたはロールバック時にクローズされます。

トランザクションの詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のトランザクションの概要に関する説明を参照してください。

自動コミットの設定

TimesTen接続は、デフォルトで自動コミットが有効になっていますが、パフォーマンス上の理由で無効にすることをお薦めします。ConnectionメソッドsetAutoCommit()を使用して、自動コミットの有効/無効を切り替えることができます。

次のように自動コミットを無効にします。

myconn.setAutoCommit(false);
// Report any SQLWarnings on the connection.
// See "Reporting errors and warnings".

ノート:

TimesTen 12cリリース以降では、setAutoCommit()コールでは、そのコールにより実際に自動コミット設定が変更された場合にのみコミットが発生します。以前のリリースでは、setAutoCommit()コールにより常にコミットが発生していました。

手動コミットまたは変更のロールバック

自動コミットが無効化された場合、Connectionメソッドcommit()を使用して手動でトランザクションをコミットするか、またはrollback()メソッドを使用して変更をロールバックする必要があります。次の例を想定してください。

myconn.commit();

または

myconn.rollback();

COMMIT文およびROLLBACK SQL文の使用

SQLのCOMMIT文およびROLLBACK文は、他のSQL文と同様に準備して実行できます。COMMIT文およびROLLBACK文の使用は、Connectionメソッドcommit()およびrollback()の使用と同じ結果になります。次に例を示します。

mystmt.execute("COMMIT");

複数スレッドの管理

level4サンプル・アプリケーションでは、複数スレッドの使用について説明します。TimesTenクイック・スタートおよびサンプル・アプリケーションを参照してください。

アプリケーションにデータベースに対する直接接続がある場合、TimesTenファンクションはアプリケーションとスタック空間を共有します。マルチスレッド環境では、デバッグが困難な予測不能な状態でプログラムが失敗する可能性があるため、各スレッドに割り当てたスタックが超過しないようにすることが重要です。TimesTenのコールが消費するスタック空間は、使用するSQLの機能によっても異なります。ほとんどのアプリケーションでは、スレッド・スタック空間を34 KBから72 KBの間で設定する必要があります。

各スレッドに割り当てられるスタック空間の量は、スレッドの作成時にオペレーティング・システムが指定します。Windowsでは、TimesTenデバッグ・ドライバを使用し、Visual C++デバッグCライブラリとアプリケーションをリンクすると、スレッドが割当て量よりもそのスタックを拡張しようとするときに識別可能な例外を発生させる、スタック・プローブが有効になります。


ノート:

マルチスレッド・アプリケーションでは、同じデータベースへの様々な接続ハンドルにリクエストを発行するスレッドで、それ自身とのロック競合が発生する可能性があります。TimesTenは、この状況でロック・タイムアウトおよびデッドロック・エラーを返します。

Javaのエスケープ構文およびSQLファンクション

JDBCでSQLを使用する際は、Javaエスケープ構文に特に注意します。UNISTRなどのSQLファンクションは、バックスラッシュ文字(\)を使用します。バックスラッシュ文字は、エスケープする必要があります。たとえば、Javaアプリケーションで次のSQL構文を使用すると、意図した結果にならない場合があります。

INSERT INTO table1 SELECT UNISTR('\00E4') FROM dual;

バックスラッシュ文字を次のようにエスケープします。

INSERT INTO table1 SELECT UNISTR('\\00E4') FROM dual;

その他のTimesTenデータ管理機能の使用

前述の項では、TimesTenデータを管理する際の主な機能について説明しました。この項では、次の追加の機能について説明します。

プロシージャおよびファンクションを実行するためのコールの使用

TimesTenでは、(スタンドアロンの場合とパッケージの一部である場合がある)PL/SQLプロシージャ(procname)またはPL/SQLファンクション(funcname)をコールする、またはTimesTen組込みプロシージャ(procname)をコールする、そのすべてのプログラミング・インタフェースの次の各構文書式をサポートしています。

CALL procname[(argumentlist)]

CALL funcname[(argumentlist)] INTO :returnparam

CALL funcname[(argumentlist)] INTO ?

TimesTenのJDBCでは、次の構文の書式もサポートしています。

{ CALL procname[(argumentlist)] }

{ ? = [CALL] funcname[(argumentlist)] }

{ :returnparam = [CALL] funcname[(argumentlist)] }

プロシージャおよびファンクションは、(結果セットをいつ返すかなどの)準備ステップがある場合はそれを先にして、CallableStatementインタフェースを介して実行します。

次の例では、TimesTen組込みプロシージャのttCkptをコールしています(より完全なJDBCの構文例については、例2-13も参照してください)。

CallableStatement.execute("call ttCkpt")

次の例では、TimesTen組込みプロシージャのttDataStoreStatusをコールしています。このプロシージャでは結果セットが生成されるため、準備コールが使用されています。(より完全なJDBCの構文例については、例2-14も参照してください)。

CallableStatement cStmt = null;
cStmt = conn.prepareCall("call ttDataStoreStatus");
cStmt.execute();

次の例では、2つのパラメータを使用し、PL/SQLプロシージャmyprocをコールしています。

cStmt.execute("{ call myproc(:param1, :param2) }");

cStmt.execute("{ call myproc(?, ?) }");

次にPL/SQLファンクションmyfuncをコールするいくつかの方法を示します。

cStmt.execute("CALL myfunc() INTO :retparam");

cStmt.execute("CALL myfunc() INTO ?");

cStmt.execute("{ :retparam = myfunc() }");

cStmt.execute("{ ? = myfunc() }");

CALL構文の詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』CALLに関する説明を参照してください。


ノート:

ユーザー独自のプロシージャは、同じ名前を持ったTimesTen組込みプロシージャより優先されますが、このような命名の競合は回避することが最適です。

例2-13 ttCkptコールの実行

この例では、ttCkptプロシージャをコールしてファジー・チェックポイントを開始します。

Connection conn = null;
CallableStatement cStmt = null;
.......
cStmt = conn.prepareCall("{ Call ttCkpt }");
cStmt.execute();
conn.commit();           // commit the transaction

ttCkpt組込みプロシージャには、ADMIN権限が必要なことに注意してください。その他の情報については、『Oracle TimesTen In-Memory Databaseリファレンス』のttCkptに関する項を参照してください。

例2-14 ttDataStoreStatusコールの実行

この例では、ttDataStoreStatusプロシージャをコールして、返される結果セットを出力します。

結果セットを返す組込みプロシージャについては、ResultSetインタフェースのgetXXX()メソッドを使用して、次のようにデータを取得できます。

「TimesTen結果セットの使用: ヒントおよび制限」に示した例とは異なり、この例では、ResultSetオブジェクトでgetString()コールを使用して、バイナリであるContextフィールドを取得します。これは、出力は処理で使用されるのではなく、表示されるためです。Context値を表示しない場合は、getBytes()メソッドをかわりに使用すると、より高いパフォーマンスが得られます。

ResultSet rs;

CallableStatement cStmt = conn.prepareCall("{ Call ttDataStoreStatus }");

if (cStmt.execute() == true) {
    rs = cStmt.getResultSet();
    System.out.println("Fetching result set...");
    while (rs.next()) {
      System.out.println("\n Database: " + rs.getString(1));
      System.out.println(" PID: " + rs.getInt(2));
      System.out.println(" Context: " + rs.getString(3));
      System.out.println(" ConType: " + rs.getString(4));
      System.out.println(" memoryID: " + rs.getString(5));
      }
    rs.close();
  }
cStmt.close();

SQL文の実行に対するタイムアウトまたはしきい値の設定

TimesTenには、SQL文の実行時間を制限する2通りの方法があり、execute()executeBatch()executeQuery()executeUpdate()またはnext()のコールで使用できます。

前者では、タイムアウト期間になると文の実行が停止しエラーがスローされる、タイムアウトを設定します。後者では、しきい値を設定し、しきい値に達するとサポート・ログに警告が書き込まれますが、実行は続行されます。

SQL文のタイムアウト期間の設定

TimesTenでは、SQLQueryTimeout一般接続属性またはSQLQueryTimeoutMsec一般接続属性(ミリ秒)を使用することで、タイムアウト値を接続、つまり接続の任意の文に対して指定できます。それぞれのデフォルト値は0で、タイムアウトはありません。(Oracle TimesTen In-Memory DatabaseリファレンスのSQLQueryTimeoutとSQLQueryTimeoutMsecも参照してください。)

名前に反して、これらのタイムアウト値は問合せだけでなく、実行可能な任意のSQL文に適用されます。

特定の文について、StatementメソッドsetQueryTimeout()をコールすることで、SQLQueryTimeout設定を上書きすることができます。

問合せのタイムアウト制限は、SQL文がアクティブに実行されている場合のみ有効です。処理のコミット中またはロールバック中にタイムアウトは発生しません。多数の行を更新、挿入、削除するトランザクションでは、コミットまたはロールバックの行程が完了するまでに時間がかかる場合があります。その間、タイムアウト値は無視されます。

他のタイムアウト設定に関連したSQL問合せタイムアウトに関する考慮事項については、Oracle TimesTen In-Memory Databaseオペレーション・ガイドのSQLおよびPL/SQLのタイムアウト値の選択を参照してください。


ノート:

ロック・タイムアウト値およびSQL問合せタイムアウト値の両方が指定されている場合は、まず、2つの値の小さい方の値によってタイムアウトが発生します。ロック・タイムアウトについては、『Oracle TimesTen In-Memory Databaseリファレンス』のttLockWait(組込みプロシージャ)またはLockWait(一般接続属性)に関する説明、またはOracle TimesTen In-Memory Databaseトラブルシューティング・ガイドのデッドロックとタイムアウトの確認に関する説明を参照してください。

SQL文のしきい値期間の設定

SQL文の実行が指定期間(秒単位)を超えた場合に、サポート・ログに警告を書き込むように、TimesTenを構成できます。実行は継続され、しきい値の影響は受けません。

名前に反して、このしきい値は問合せだけでなく、SQL文を実行する任意のJDBCコールに適用されます。

デフォルトでは、アプリケーションはしきい値をQueryThreshold一般接続属性設定から取得します。デフォルトは0 (警告なし)です。データベースの接続URLにQueryThreshold属性を含めることでJDBC Connectionオブジェクトのしきい値を上書きすることができます。たとえば、QueryThresholdの値をmyDSNデータベース用に5秒に設定するには、次のようにします。

jdbc:timesten:direct:dsn=myDSN;QueryThreshold=5

TimesTenStatementオブジェクトのsetQueryTimeThreshold()メソッドを使用して、しきい値を設定することもできます。これは、接続属性設定およびConnection オブジェクト設定を上書きします。

TimesTenStatementオブジェクトのgetQueryTimeThreshold()メソッドを使用して現行のしきい値を取得できます。

詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

TimesTen Cacheで使用する機能

この項では、TimesTen ClassicでのTimesTen Application-Tier Database Cache (TimesTen Cache)の使用に関係する機能について説明します。


ノート:

OraclePassword属性は、Oracle Databaseパスワードにマップされます。TimesTenDataSourceメソッドsetOraclePassword()を使用してOracle Databaseのパスワードを設定できます。例は、「データベースへの接続」を参照してください。

ttOptSetFlag組込みプロシージャでの一時パススルー・レベルの設定

TimesTenでは、パススルー・レベルを一時的に設定するPassThroughフラグを含め、様々なフラグの設定にttOptSetFlag組込みプロシージャを用意しています。ttOptSetFlagを使用すると、次のサンプル文のようにJDBCアプリケーションでPassThroughを設定できます(この場合、パススルー・レベルは1に設定されます)。この設定は、トランザクションの最後までの準備されているすべての文に影響します。

pstmt = conn.prepareStatement("call ttoptsetflag('PassThrough', 1)");

次の例には、これらのステップを実行するサンプル・コードがあります。

  1. パススルー・レベル用に、バインド・パラメータを使用するttOptSetFlagをコールする準備済文(PreparedStatementインスタンスthePassThroughStatement)を作成します。

  2. 指定したパススルー設定を取るメソッドsetPassthrough()を定義し、これを準備済文にバインドし、準備済文を実行して、パススルー・レベルを設定するttOptSetFlagをコールします。

  thePassThroughStatement = 
         theConnection.prepareStatement("call ttoptsetflag('PassThrough', ?)");
  ...
  private void setPassthrough(int level) throws SQLException{
    thePassThroughStatement.setInt(1, level);
    thePassThroughStatement.execute();
  }

この組込みプロシージャの詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のttOptSetFlagに関する説明を参照してください。

この一般接続属性の詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のパススルーに関する説明を参照してください。パススルー設定の詳細は、『Oracle TimesTen Application-Tier Database Cacheユーザーズ・ガイド』のパススルー・レベルの設定に関する説明を参照してください。

パススルー・ステータスの確認

SQL文がTimesTenデータベースで実行されるかそれとも実行のためにOracleデータベースにパススルーされるかを判断するために、TimesTenPreparedStatementメソッドgetPassThroughType()をコールできます。

PassThroughType getPassThroughType()

戻り値の型であるTimesTenPreparedStatement.PassThroughTypeは、TimesTen PassThrough接続属性の値の列挙型です。

SQL文の準備の後に、このコールを実行できます。これは、PassThrough設定1または2の場合(文が実際にパススルーされるかどうかの確認がコンパイル時まで行われない)に有効です。

PassThrough設定の詳細は、『Oracle TimesTen Application-Tier Database Cacheユーザーズ・ガイド』のパススルー・レベルの設定に関する説明を参照してください。

キャッシュ・グループの管理

TimesTenで、FLUSH CACHE GROUPLOAD CACHE GROUPREFRESH CACHE GROUPまたはUNLOAD CACHE GROUP文を実行すると、StatementメソッドgetUpdateCount()によって、フラッシュ、ロード、リフレッシュ、アンロードされたキャッシュ・インスタンスの数が返されます。

関連する情報について、『Oracle TimesTen Application-Tier Database Cacheユーザーズ・ガイド』の操作で影響を受けたキャッシュ・インスタンスの数の判別に関する説明を参照してください。

レプリケーションで使用する機能

レプリケーションを使用するTimesTen Classicアプリケーションの場合、パラレル・レプリケーションを使用することでパフォーマンスを向上させることができます。パラレル・レプリケーションでは、並行して動作する複数のスレッドを使用して、レプリケーション・スキーム内のデータベースにトランザクションの変更をレプリケートおよび適用します。TimesTenでは、次のタイプのパラレル・レプリケーションをサポートしています。

  • 自動パラレル・レプリケーション(ReplicationApplyOrdering=0): トランザクションの依存性と、コミット順に適用されたすべての変更を自動的に強制する、複数のスレッドにおけるパラレル・レプリケーション。これはデフォルトです。

  • コミット依存性を無効にした自動パラレル・レプリケーション(ReplicationApplyOrdering=2): トランザクションの依存性を自動的に強制するが、サブスクライバ・データベース上でマスター・データベース上と同じ順序でコミットされるトランザクションは強制しない、複数スレッドでのパラレル・レプリケーション。このモードでは、オプションでレプリケーション・トラックを指定できます。

詳細および使用方法のシナリオについては、『Oracle TimesTen In-Memory Database開発者および管理者ガイド』のパラレル・レプリケーションの構成に関する説明を参照してください。

パラレル・レプリケーションを使用し、レプリケーション・トラックを指定するJDBCアプリケーションの場合は、後述のTimesTenConnectionメソッドを通じて、接続でトラック番号を指定できます。(または、一般接続属性のReplicationTrackまたはALTER SESSIONパラメータREPLICATION_TRACKを使用します)。

  • void setReplicationTrack(int track)

TimesTenConnectionにも、対応するgetterメソッドがあります。

  • int getReplicationTrack()

詳細は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』を参照してください。

エラー処理

この項では、TimesTen Javaアプリケーションで発生するエラーの検出、識別および処理について説明します。

TimesTenにより返されるエラーのリストおよびエラーが発生した場合の対処方法については、『Oracle TimesTen In-Memory Databaseエラー・メッセージおよびSNMPトラップ』の警告およびエラーに関する章を参照してください。

この項の内容は次のとおりです。

致命的エラー、致命的でないエラーおよび警告

操作が完全には成功しない場合、TimesTenは、致命的なエラー、致命的ではないエラーまたは警告を返すことができます。

致命的エラーの処理

致命的なエラーが発生すると、リカバリするまでデータベースにアクセスできなくなります。致命的なエラーが発生すると、すべてのデータベースの接続を切断する必要があります。それ以後の処理は完了されません。致命的エラーは、TimesTenのエラー・コード846および994で示されます。これらのエラーの処理は、標準的なエラーの処理とは異なります。特に、コードで現行のトランザクションをロールバックし、サーバーでのメモリー不足状態を避けるためにデータベースからの接続を切断する必要があります。古いTimesTenインスタンスの共有メモリーは、エラー発生時にアクティブだったすべての接続が切断されるまで解放されません。古いTimesTenインスタンスに引き続き接続されている非アクティブなアプリケーションは、手動で終了する必要があることがあります。

致命的エラーが発生した場合、TimesTenは、次の完全なクリーンアップおよびリカバリ・プロシージャを実行します。

  • データベースに対するすべての接続を無効し、新しいメモリー・セグメントを割り当て、アプリケーションを切断します。

  • その後の最初の初期接続時に、チェックポイント・ファイルおよびトランザクション・ログ・ファイルからデータベースをリカバリします。

    • リカバリされたデータベースには、永続コミットされたすべてのトランザクションの状態が反映され、非永続的にコミットされた一部のトランザクションも反映されます。

    • コミットされていないトランザクションまたはロールバックされたトランザクションは反映されません。

致命的ではないエラーの処理

致命的ではないエラーには、一意制約に違反しているINSERT文などの単純なエラーが含まれます。また、一部のアプリケーション障害およびプロセス障害も、致命的ではないエラーに含まれます。

TimesTenは、通常のエラー処理プロセスを介して致命的ではないエラーを返します。アプリケーションは、エラーがないか確認し、これらを適切に処理する必要があります。

致命的ではないエラーによってデータベースに影響が出た場合、エラーが返されることがあり、アプリケーションで適切に対処する必要があります。

アプリケーションでは、その処理を変更するか、または障害が発生した1つ以上のトランザクションをロールバックすることによって、致命的ではないエラーに対処できます。詳細は、「失敗したトランザクションのロールバック」を参照してください。

後述の「エラーおよび警告のレポート」も参照してください。


ノート:

ResultSetStatementPreparedStatementCallableStatementまたはConnection操作でデータベースにエラーが発生する場合は、そのオブジェクトに対してclose()メソッドをコールすることをお薦めします。

警告について

TimesTenは予期しない問題が発生した場合に警告を返します。たとえば、次の状況が発生した場合、TimesTenは警告を発行します。

  • チェックポイントの障害

  • 非推奨のTimesTen機能の使用

  • 一部のデータの切捨て

  • 接続時のリカバリ処理の実行

  • レプリケーションがRETURN RECEIPTの場合のタイムアウト

アプリケーションの問題を示すことができるように、警告をチェックするコードを常に含める必要があります。

すぐ下の「エラーおよび警告のレポート」も参照してください。

異常終了

プロセスの障害などの場合はエラーが返されないため、失敗したプロセスのトランザクションが自動的にロールバックされます。

エラーおよび警告のレポート

コールのたびに返される可能性があるすべてのエラーと警告を確認してレポートする必要があります。これによって、開発およびデバッグの時間および労力が大幅に削減されます。データベースのアクセス時にエラーが1つ以上ある場合は、SQLExceptionオブジェクトが発生し、警告メッセージが1つ以上ある場合は、SQLWarningオブジェクトが発生します。1回のコールで複数のエラーまたは警告(あるいはその両方)が返されることがあるため、アプリケーションでは、返されたSQLExceptionオブジェクトまたはSQLWarningオブジェクトにすべてのエラーまたは警告をレポートする必要があります。

SQLExceptionオブジェクトまたはSQLWarningオブジェクトのリンク連鎖では、複数のエラーまたは警告が返されます。例2-15および例2-16に、返されたSQLExceptionオブジェクトとSQLWarningオブジェクトのリストで繰り返し実行し、それぞれにすべてのエラーと警告をレポートする方法を示します。

例2-15 例外の表示

次のメソッドは、リンクされたSQLExceptionオブジェクトのすべての例外の内容を表示します。

static int reportSQLExceptions(SQLException ex)
  {
    int errCount = 0;
    if (ex != null) {
      errStream.println("\n--- SQLException caught ---");
      ex.printStackTrace();

      while (ex != null) {
        errStream.println("SQL State: " + ex.getSQLState());
        errStream.println("Message: " + ex.getMessage());
        errStream.println("Error Code: " + ex.getErrorCode());
        errCount ++;
        ex = ex.getNextException();
        errStream.println();
      }
    }

    return errCount;
}

例2-16 警告の表示

このメソッドは、リンクされたSQLWarningオブジェクトのすべての例外の内容を表示します。

static int reportSQLWarnings(SQLWarning wn)
{
    int warnCount = 0;

    while (wn != null) {
      errStream.println("\n--- SQL Warning ---");
      errStream.println("SQL State: " + wn.getSQLState());
      errStream.println("Message: " + wn.getMessage());
      errStream.println("Error Code: " + wn.getErrorCode());

      // is this a SQLWarning object or a DataTruncation object?
      if (wn instanceof DataTruncation) {
        DataTruncation trn = (DataTruncation) wn;
        errStream.println("Truncation error in column: " +
          trn.getIndex());
      }
      warnCount++;
      wn = wn.getNextWarning();
      errStream.println();
    }
    return warnCount;
}

特定のエラーの検出および対応

一部の状況では、特定のSQLの状態またはTimesTenエラー・コードに応答することが望ましい場合があります。SQLExceptionメソッドgetSQLState()を使用すると、例2-17のように、SQLの状態を戻すことができ、getErrorCode()メソッドを使用すると、TimesTenエラー・コードを戻すことができます。

エラーの情報は、『Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference』TimesTenVendorCodeに関する項も参照してください。

例2-17 エラーの検出

TimesTen Classicクイック・スタート・サンプル・アプリケーションでは、スキーマをロードしてから実行する必要があります。ODBCエラーS0002およびTimesTenエラー907が検出されると、次のcatch文により、appuserがロードまたは更新されていないというアラートがユーザーに発行されます。

catch (SQLException ex) {
  if (ex.getSQLState().equalsIgnoreCase("S0002")) {
    errStream.println("\nError: The table appuser.customer " +
      "does not exist.\n\t Please reinitialize the database.");
  } else if (ex.getErrorCode() == 907) {
    errStream.println("\nError: Attempting to insert a row " +
      "with a duplicate primary key.\n\tPlease reinitialize the database.");
}

TimesTenVendorCodeインタフェースを使用すると、番号ではなく名前によって、エラーを検出できます。

次の例を検討してください。

ex.getErrorCode() == com.timesten.jdbc.TimesTenVendorCode.TT_ERR_KEYEXISTS

次が同等です。

ex.getErrorCode() == 907

失敗したトランザクションのロールバック

デッドロックからのリカバリやロック・タイムアウトなど、いくつかの状況では、次の例のようにConnectionのメソッドrollback()を使用して、トランザクションを明示的にロールバックする必要があります。

例2-18 トランザクションのロールバック

try {
  if (conn != null && !conn.isClosed()) {
    // Rollback any transactions in case of errors
      if (retcode != 0) {
        try {
          System.out.println("\nEncountered error. Rolling back transaction");
          conn.rollback();
        } catch (SQLException ex) {
          reportSQLExceptions(ex);
        }
      }
   }

    System.out.println("\nClosing the connection\n");
    conn.close();
} catch (SQLException ex) {

  reportSQLExceptions(ex);
}

トランザクションのロールバックによってリソースが消費され、結果的にトランザクション全体が無駄になってしまいます。不要なロールバックを回避するには、競合が発生しないようにアプリケーションを設計し、送信前にアプリケーションまたは入力データをチェックしてエラーを検出する必要があります。


ノート:

アクティブなトランザクションの途中でアプリケーションが中断、クラッシュまたは切断した場合、TimesTenはトランザクションを自動的にロールバックします。

一時エラー後の再試行(JDBC)

TimesTenではほとんどの一時エラーは自動的に解決されますが(これはTimesTen Scaleoutにおいてとりわけ重要です)、アプリケーションで次のSQLSTATE値が検出された場合は、現在のトランザクションを再試行することをお薦めします。

  • TT005: Transient transaction failure due to unavailability of resource.Roll back the transaction and try it again.


ノート:

再試行が妥当かどうかを判断する前に、エラー・スタック全体でこれらのエラー・タイプを返すエラーを検索してください。

これはSQLExceptionクラスのgetSQLState()メソッドによって返されるもので、次のいずれかのJDBC型のメソッド・コールにより発生する場合があります。

  • Connection

  • Statement

  • PreparedStatement

  • CallableStatement

  • ResultSet

  • Connection

  • Statement

  • PreparedStatement

  • CallableStatement

  • ResultSet

次に例を示します。

// Database connection object
Connection        dbConn;
 
// Open the connection  to the database
...
 
// Disable auto-commit
dbConn.setAutoCommit( false ); 
 
...
 
// Prepre the SQL statements
PreparedStatement stmtQuery = dbConn.prepare("SELECT ...");
PreparedStatement stmtUpdate = dbConn.prepare("UPDATE ...");
 
...
 
// Set max retries for transaction to 5
int retriesLeft = 5;
 
// Records outcome
boolean success = false;
 
// Excute transaction with retries until success or retries exhausted
while (  retriesLeft > 0  )
{
    try {
 
        // First execute the query
 
        // Set input values
        stmtQuery.setInt(1, ...);
        stmtQuery.setString(2, ...);
 
        // Execute and process results
        ResultSet rs = stmtQuery.executeQuery();
        while (  rs.next()  )
        {
            int val1 = rs.getInt(1);
            String val2 = rs.getString(2);
            ...
        }
        rs.close();
        rs = null;
          
        // Now excute the update
 
        // Set input values
        stmtUpdate.setInt(1,...);
        stmtUpdate.setString(2,...);
 
        // Execute and check number of rows affected
        int updCount = stmtUpdate.executeUpdate();
        if (  updCount < 1  )
        {
            ...
        }
 
        // And finally commit
        dbConn.commit();
 
        // We are done
        success = true;
        break;
 
    } catch ( SQLException sqe ) {
 
        if (  sqe.getSQLState().equals("TT005")  ) // grid transient error
        {
            // decrement retry count
            retriesLeft--;
            // and rollback the transaction ready for retry
            try {
                dbConn.rollback();
            } catch ( SQLException sqer ) {
                // This is a fatal error so handle accordingly
            }
        }
        else
        {
            // handle other kinds of error
            ...
        }
    }
} // end of retry loop
 
if (  ! success  )
{
    // Handle the failure
    ...
}

ノート:

フェイルオーバー遅延と再試行の設定例2-22では、一時的なエラーの場合の再試行方法も示しています。

自動クライアント・フェイルオーバーのJDBCサポート

自動クライアント・フェイルオーバーは、TimesTen ScaleoutまたはTimesTen Classicの高可用性のシナリオにおいて使用されます。TimesTen Classicには、2つのシナリオがあります。1つはアクティブ・スタンバイ・ペアのレプリケーションを使用し、もう1つは汎用自動クライアント・フェイルオーバーと呼ばれます。

クライアントが接続しているデータベースまたはデータベース要素に障害が発生した場合は、代替データベースまたは代替データベース要素にフェイルオーバー(接続転送)します。

  • TimesTen Scaleoutの場合、グリッド内の使用可能な要素のリストにある要素にフェイルオーバーします。

  • アクティブ・スタンバイ・レプリケーションを使用するTimesTen Classicの場合、新しいアクティブ(元のスタンバイ)データベースにフェイルオーバーします。

  • 汎用自動クライアント・フェイルオーバーを使用するTimesTen Classicの場合、スキーマおよびデータが両方のデータベースで一貫していることを確認でき、クライアントのodbc.iniファイルで構成されているリスト内のデータベースにフェイルオーバーします。

    汎用自動フェイルオーバーの一般的なユースケースは、読取り専用キャッシュを使用する一連のデータベースで、各データベースのキャッシュ・データ・セットは同じです。たとえば、読取り専用キャッシュ・グループが複数ある場合は、フェイルオーバー・サーバーのリストに含まれるすべてのTimesTen Classicデータベースに、同じ読取り専用キャッシュ・グループを作成します。クライアント接続が代替のTimesTenデータベースにフェイルオーバーされると、TimesTen Cacheは(必要に応じて) Oracle Databaseからのデータを自動的にリフレッシュするため、キャッシュ・データの一貫性が保たれます。

アプリケーションは、新規データ・データベースまたはデータベース要素に自動的に再接続されます。TimesTenは自動クライアント・フェイルオーバーが発生したときに、アプリケーションに警告を渡す機能を提供しているため、アプリケーションは適切な処理を行うことができます。

次のエラー条件はいずれも、自動クライアント・フェイルオーバーを示します。

  • SQL状態08006のネイティブ・エラー30105

  • ネイティブ・エラー47137

この項では、自動クライアント・フェイルオーバーに関連するTimesTen JDBC拡張について説明します。次の内容について説明します。

TimesTen Scaleoutの場合、詳細はOracle TimesTen In-Memory Database Scaleoutユーザーズ・ガイドのクライアント接続フェイルオーバーを参照してください。TimesTen Classicの場合は、Oracle TimesTen In-Memory Databaseオペレーション・ガイドの自動クライアント・フェイルオーバーの使用を参照してください。開発者向けの関連情報については、Oracle TimesTen In-Memory Database C開発者ガイドの自分のアプリケーションでの自動クライアント・フェイルオーバーの使用を参照してください。


ノート:

  • 自動クライアント・フェイルオーバーは、クライアント/サーバー接続にのみ適用されます。ここで説明する機能は、直接接続には使用できません。

  • Oracle Clusterwareを使用する場合、自動クライアント・フェイルオーバーはOracle Clusterwareに対する補完機能ですが、この2つの機能は互いに依存しません。Oracle Clusterwareの詳細は、『Oracle TimesTen In-Memory Database開発者および管理者ガイド』のOracle Clusterwareを使用してのアクティブ・スタンバイ・ペアの管理に関する項を参照してください。


自動クライアント・フェイルオーバーのJDBCサポートの特徴および機能

この項では、クライアント・フェイルオーバーに関係する一般的なTimesTen JDBC機能(特にプールされた接続に関係する機能)について説明します。

ここで説明するTimesTenのJDBCクラス、インタフェース、メソッドの詳細は、Oracle TimesTen In-Memory Database JDBC拡張Java APIリファレンスを参照してください。

一般的なクライアント・フェイルオーバー機能

自動クライアント・フェイルオーバーに対するTimesTen JDBCサポートには、フェイルオーバーを検出するために次の2つのメカニズムがあります。

  • SQL例外での同期検出: 自動クライアント・フェイルオーバー後、障害が発生した接続に作成された文、準備済文、コール可能な文および結果セットなどのJDBCオブジェクトは使用できなくなります。そのようなオブジェクトにアプリケーションがアクセスを試みた場合、Java SQL例外がスローされます。その例外のSQL状態およびエラーコードを確認することで、例外が、フェイルオーバーの状況の結果であるかどうかを判断できます。

  • イベント・リスナーでの非同期検出: アプリケーションでは、フェイルオーバーのプロセスで発生する各イベントの通知対象となるユーザー定義のクライアント・フェイルオーバー・イベント・リスナーを登録できます。

TimesTen JDBCは、パッケージcom.timesten.jdbcで自動クライアント・フェイルオーバーをサポートするために次の機能を提供します。

  • ClientFailoverEventクラス

    このクラスは、クライアント・フェイルオーバー中に発生したイベント(開始、終了、中止または再試行)を表現するために使用されます。

  • ClientFailoverEventListenerインタフェース

    クライアントのフェイルオーバー・イベントが関係するアプリケーションでは、クライアントのフェイルオーバー・イベントをリスニングするメカニズムである、このインタフェースを実装するクラスを含める必要があります。アプリケーションの実行時に、TimesTen接続を介してClientFailoverEventListenerインスタンスを登録する必要があります(直下を参照)。

    リスナーを使用すると、障害の検出時に、接続プール文キャッシュのリフレッシュなどを行って積極的に対応できます。

  • TimesTenConnectionインタフェースのメソッド

    このインタフェースはメソッドaddConnectionEventListener()およびremoveConnectionEventListener()を指定し、それぞれクライアント・フェイルオーバー・イベント・リスナーの登録または削除を行います。

  • TimesTenVendorCodeインタフェースの新しい定数TT_ERR_FAILOVERINVALIDATION

    これは、イベントがフェイルオーバー・イベントであると確認できます。

プールされた接続のクライアント・フェイルオーバー機能

TimesTenでは、プールされた接続(javax.sql.PooledConnection)または接続プール・データソース(javax.sql.ConnectionPoolDataSource)を使用するアプリケーションで、前述の同期メカニズムを使用し、障害が発生した接続で失効したオブジェクトを処理することをお薦めします。プールされた接続はJava EEアプリケーション・サーバーで管理するため、プールされた接続でのイベントをアプリケーションでリスニングすることはできません。また、アプリケーション・サーバーでは、TimesTenの拡張であるClientFailoverEventListenerのインスタンスの実装および登録を行いません。

自動クライアント・フェイルオーバーの構成

TimesTenでのクライアント接続フェイルオーバーの管理の詳細は、Oracle TimesTen In-Memory Databaseオペレーション・ガイドのTimesTen Classicの自動クライアント・フェイルオーバーの構成またはOracle TimesTen In-Memory Database Scaleoutユーザーズ・ガイドのクライアント接続フェイルオーバーを参照してください。

TimesTen Classicでは、フェイルオーバーDSNは、TTC_Server2接続属性とTTC_Servern接続属性を使用して具体的に構成する必要があります。


ノート:

TTC_Server2TTC_Server_DSN2TTC_ServernまたはTCP_Port2のいずれかを設定することは、自動クライアント・フェイルオーバーを使用することを意味します。アクティブ・スタンバイ・ペアのシナリオの場合は、アプリケーションでフェイルオーバー・メカニズムをサポートできるように新しいスレッドが作成されることも意味します。

次のTimesTen接続属性に注意してください。

  • TTC_NoReconnectOnFailover: この値が1に設定されている(有効になっている)場合、TimesTenでは自動再接続以外の、すべての通常のクライアント・フェイルオーバー処理を実行します。(たとえば、文および接続ハンドルは無効としてマークされます。)これは、アプリケーションが独自に接続プーリングを行ったり、フェイルオーバー後のデータベースへの再接続を独自に管理している場合に便利です。デフォルト値は0 (再接続)です。Oracle TimesTen In-Memory DatabaseリファレンスのTTC_NoReconnectOnFailoverも参照してください。

  • TTC_REDIRECT: この値が0に設定されていて、必要なデータベースまたはデータベース要素への最初の接続試行に失敗した場合、エラーが返されそれ以上の接続試行は行われません。これは、その接続におけるその後のフェイルオーバーには影響しません。Oracle TimesTen In-Memory DatabaseリファレンスのTTC_REDIRECTも参照してください。

  • TTC_Random_Selection: 汎用自動クライアント・フェイルオーバーを使用するTimesTen Classicの場合、デフォルト設定の1 (有効)では、フェイルオーバーが発生したときに、クライアントがTTC_Servern属性の設定で指定されたリストから代替サーバーをランダムに選択します。選択したサーバーにクライアントが接続できない場合、クライアントはリストされているサーバーのいずれかに正常に接続するまでリダイレクトし続けます。0を設定すると、TimesTenはTTC_Servernサーバーのリストを順番に処理します。Oracle TimesTen In-Memory DatabaseリファレンスのTTC_Random_Selectionも参照してください。


ノート:

これらのいずれかをodbc.iniまたは接続文字列で設定すると、設定はフェイルオーバー接続に適用されます。これらはアプリケーション(ALTER SESSIONを含む)では設定できません。

自動クライアント・フェイルオーバーの同期検出

フェイルオーバー時に、障害が発生した接続に作成されたオブジェクトをアプリケーションで使用しようとすると、JDBCはSQL例外をスローします。ベンダー固有の例外コードは、TimesTenVendorCode.TT_ERR_FAILOVERINVALIDATIONに設定されます。

このメカニズムによるフェイルオーバーの検出は、同期検出として示されます。次の例でこれを説明します。

例2-19 自動クライアント・フェイルオーバーの同期検出

try {
   // ...
   // Execute a query on a previously prepared statement.
   ResultSet theResultSet = theStatement.executeQuery("select * from dual");
   // ...

} catch (SQLException sqlex) {
   sqlex.printStackTrace();
   if (sqlex.getErrorCode() == TimesTenVendorCode.TT_ERR_FAILOVERINVALIDATION) {
   // Automatic client failover has taken place; discontinue use of this object.
   }
}

自動クライアント・フェイルオーバーの非同期検出

非同期のフェイルオーバーの検出には、アプリケーションでクライアント・フェイルオーバー・イベント・リスナーを実装し、そのインスタンスをTimesTen接続に登録する必要があります。この項では、そのステップを説明します。

  1. クライアント・フェイルオーバー・イベント・リスナーを実装します

  2. クライアント・フェイルオーバー・リスナー・インスタンスを登録します

  3. クライアント・フェイルオーバー・リスナー・インスタンスを削除します

クライアント・フェイルオーバー・イベント・リスナーの実装

TimesTen JDBCは、(次のメソッドで強調されている)イベントのリスニングに使用するcom.timesten.jdbc.ClientFailoverEventListenerインタフェースを提供します。

  • void notify(ClientFailoverEvent event)

非同期フェイルオーバー検出を使用するには、このインタフェースを実装するクラスを作成した後、TimesTen接続の実行時に、クラスのインスタンスを登録する必要があります(概要が説明されています)。

フェイルオーバー・イベントが発生すると、TimesTenは、登録したリスナー・インスタンスのnotify()メソッドをコールして、イベントに関する情報を確認することができるClientFailoverEventインスタンスを提供します。

次の例は、ClientFailoverEventListener実装の基本的な形式を示しています。

例2-20 自動クライアント・フェイルオーバーの非同期検出

   private class MyCFListener implements ClientFailoverEventListener {
      /* Applications can build state system to track states during failover.
         You may want to add methods that talks about readiness of this Connection
         for processing. 
      */
      public void notify(ClientFailoverEvent event) {
         
         /* Process connection failover type */
         switch(event.getTheFailoverType()) {
         case TT_FO_CONNECTION:
            /* Process session fail over */
            System.out.println("This should be a connection failover type " +
                                event.getTheFailoverType());
            break;
            
         default:
            break;
         }
         /* Process connection failover events */
         switch(event.getTheFailoverEvent()) {
         case BEGIN:
            System.out.println("This should be a BEGIN event " +
                                event.getTheFailoverEvent());
            /* Applications cannot use Statement, PreparedStatement, ResultSet,
               etc. created on the failed Connection any longer.
            */
            break;
            
         case END:
            System.out.println("This should be an END event " +
                                event.getTheFailoverEvent());
            
            /* Applications may want to re-create Statement and PreparedStatement
               objects at this point as needed.
            */
            break;
         
         case ABORT:
            System.out.println("This should be an ABORT event " +
                                event.getTheFailoverEvent());
            break;
            
         case ERROR:
            System.out.println("This should be an ERROR event " +
                                event.getTheFailoverEvent());
            break;
            
         default:
            break;
         }
      }
   }

event.getTheFailoverType()コールは、ネストされた列挙型のクラスClientFailoverEvent.FailoverTypeのインスタンスを返します。TimesTenでは唯一サポートされる値は、接続のフェイルオーバーを示すTT_FO_CONNECTIONです。

event.getTheFailoverEvent()コールは、ネストされたクラスClientFailoverEvent.FailoverEventのインスタンスを返します。これは列挙型で、その値は次のいずれかにあります。

  • クライアント・フェイルオーバーが開始した場合は、BEGIN

  • クライアント・フェイルオーバーが正常に完了した場合は、END

  • クライアントのフェイルオーバーは失敗したが、再試行される場合は、ERROR

  • クライアント・フェイルオーバーが中断した場合は、ABORT

クライアント・フェイルオーバー・リスナー・インスタンスの登録

実行時、フェイルオーバー・イベント・リスナー・クラスのインスタンスを、TimesTen接続オブジェクトに登録する必要があります。そうすることで、フェイルオーバー・イベントに必要な、そのリスナー・クラスのnotify()メソッドをコールすることができるようになります。

これを実行するため、TimesTenConnectionには、次のメソッドがあります。

  • void addConnectionEventListener
    (ClientFailoverEventListener
    listener)

リスナー・クラスのインスタンスを作成した後、このメソッドを使用して登録します。次の例では、接続を確立した後にリスナーを登録します。theDsnがTimesTenクライアント/サーバー・データベースのJDBC URLで、theCFListenerがフェイルオーバー・イベント・リスナー・クラスのインスタンスだと仮定します。

例2-21 クライアント・フェイルオーバー・リスナーの登録

      try {
         /* Assume this is a client/server conn; register for conn failover. */
         Class.forName("com.timesten.jdbc.TimesTenClientDriver");
         String url = "jdbc:timesten:client:" + theDsn;
         theConnection = (TimesTenConnection)DriverManager.getConnection(url);
         theConnection.addConnectionEventListener(theCFListener);
         /* Additional logic goes here; connection failover listener is
            called if there is a fail over.
         */
      }
      catch (ClassNotFoundException cnfex) {
         cnfex.printStackTrace();
      }
      catch (SQLException sqlex) {
         sqlex.printStackTrace();
      }

クライアント・フェイルオーバー・リスナー・インスタンスの削除

TimesTenConnectionインタフェースは次のメソッド定義して、フェイルオーバー・イベント・リスナーを登録解除します。

  • void removeConnectionEventListener
    (ClientFailoverEventListener
    listener)

リスナー・インスタンスを登録解除する場合は、このメソッドを使用します。

フェイルオーバー・イベント時のアプリケーションのアクション

この項の内容は次のとおりです。

フェイルオーバーのためのアプリケーションのステップ

アプリケーションでの操作に対するレスポンスで自動クライアント・フェイルオーバーのJDBCサポートの自動クライアント・フェイルオーバーに関する説明の最初に記載されているいずれかのエラー条件が発生した場合、アプリケーション・フェイルオーバーが進行中です。次のリカバリ操作を実行します。

  1. 接続のすべてのトランザクションをロールバックします。

  2. 前の接続からのすべてのオブジェクトをクリーン・アップします。前の接続に関連付けられている状態やオブジェクトはいずれも保持されません。

  3. TTC_NoReconnectOnFailover=0 (デフォルト)の場合、次のセクションのフェイルオーバー遅延と再試行の設定で説明されているように、短時間スリープします。TTC_NoReconnectOnFailover=1の場合は、かわりにアプリケーションを手動で代替データベースまたはデータベース要素に再接続する必要があります。

  4. 接続に関連するすべてのオブジェクトを再作成して再度準備します。

  5. 進行中のトランザクションを最初から再開します。

フェイルオーバー遅延と再試行の設定

自動クライアント・フェイルオーバー中に別のデータベースまたはデータベース要素に再接続する場合、時間がかかることがあります。TimesTenがクライアント・フェイルオーバー・プロセスを完了する前にアプリケーションがリカバリ・アクションを試みた場合、自動クライアント・フェイルオーバーのJDBCサポートの自動クライアント・フェイルオーバーに関する内容の最初にリストされている他のフェイルオーバー・エラー条件が発生する可能性があります。

したがって、アプリケーションでは後続の各試行に先立つ、多少の遅れを伴う1度のループにおいてすべてのリカバリ・アクションを行う必要があり、試行の合計数には制限を設けます。試行回数を制限しないと、クライアント・フェイルオーバー・プロセスが正常に完了しなかった場合にアプリケーションがハングしたように見える場合があります。たとえば、リカバリ・ループについて再試行の遅延を100ミリ秒、最大再試行回数の制限を100回にできます。理想的な値はそれぞれのアプリケーションおよび構成によって異なります。

例2-22ではこの点を示しています。

例2-22 JDBCでのクライアント・フェイルオーバーの再試行

同期検出方法を使用する次のコード・スニペットは、JDBCアプリケーションの接続フェイルオーバー・エラーの再試行を処理する方法を示しています。直接関係のないコードは省略(...)されています。

// Database connection object
Connection        dbConn;
 
// Open the connection  to the database
...
 
// Disable auto-commit
dbConn.setAutoCommit( false ); 
 
...
 
// Prepre the SQL statements
PreparedStatement stmtQuery = dbConn.prepare("SELECT ...");
PreparedStatement stmtUpdate = dbConn.prepare("UPDATE ...");
 
...
 
// Set max retries to 100
int retriesLeft = 100;
// and retry delay to 100 ms
int retryDelay = 100;
 
// Records outcome
boolean success = false;
Boolean needReprepare = false;
 
// Execute transaction with retries until success or retries exhausted
while (  retriesLeft > 0  )
{
    try {
 
        // Do we need to re-prepare
        if ( needReprepare )
        {
            Thread.sleep( retryDelay ); // delay before proceeding
            stmtQuery = dbConn.prepare("SELECT ...");
            stmtUpdate = dbConn.prepare("UPDATE ...");
            needReprepare = false;
        }
 
        // First execute the query
 
        // Set input values
        stmtQuery.setInt(1, ...);
        stmtQuery.setString(2, ...);
 
        // Execute and process results
        ResultSet rs = stmtQuery.executeQuery();
        while (  rs.next()  )
        {
            int val1 = rs.getInt(1);
            String val2 = rs.getString(2);
            ...
        }
        rs.close();
        rs = null;
          
        // Now execute the update
 
        // Set input values
        stmtUpdate.setInt(1,...);
        stmtUpdate.setString(2,...);
 
        // Execute and check number of rows affected
        int updCount = stmtUpdate.executeUpdate();
        if (  updCount < 1  )
        {
            ...
        }
 
        // And finally commit
        dbConn.commit();
 
        // We are done
        success = true;
        break;
 
    } catch ( SQLException sqe ) {
 
       if (  (sqe.getErrorCode() == 47137) ||
             ( (sqe.getErrorCode() == 30105) && (sqe.getSQLState().equals("08006")) )  )
        // connection failover error
        {
            // decrement retry count
            retriesLeft--;
            // rollback the transaction ready for retry
            dbConn.rollback();
            // and indicate that we need to re-prepare
            needReprepare = true;
        }
        else
        {
            // handle other kinds of error
            ...
        }
 
    }
 
} // end of retry loop if (  ! success  ){    // Handle the failure    ...}

TimesTen Scaleoutでのクライアント・ルーティング

パフォーマンスを向上させるために、TimesTen Scaleoutでは、クライアント・アプリケーションにおいて接続を要素にハッシュ分散キーのキー値に基づいてルーティングできます。分散キーのキー値を指定すると、TimesTen Scaleoutはデータベースによりその値が割り当てられている要素ID (またはレプリカ・セットID)の配列を戻します。これにより、クライアント・アプリケーションは指定されたキー値を持つ行が格納されている要素に接続できるようになり、行が格納されている要素とアプリケーションに接続されている要素との間で不要な通信が発生するのを回避できます。

この項の内容は次のとおりです。

分散キーの作成

クライアント・アプリケーションは、分散キーを識別および作成する必要があります。これは特定のキー値のセットを割り当てる要素(またはレプリカ・セット)を特定するのに必要です。TimesTenDistributionKeyおよびTimesTenDistributionKeyBuilderインタフェースは、分散キーを作成するための機能を指定します。


ノート:

アプリケーションは、分散キーの作成、要素IDまたはレプリカ・セットIDの計算、およびこの3つのいずれかに基づくデータベースの要素への接続の作成のために、データベースへのクライアント接続を保持する必要があります(例2-23および例2-24を参照)。

TimesTenDistributionKeyBuilderインタフェースでは次のビルダー・メソッドを指定して、データ型が異なる複合キーをサポートします。

subkey(Object subkey, java.sql.Types subkeyType)

複合分散キーの場合、表のハッシュ分散キーのすべての列に対してsubkeyメソッドを1回ずつ呼び出します。各subkeyを、表の分散キー列のキー値およびタイプと同じ順序で起動します。

指定されたキー値セットの要素の場所の取得

分散キーを作成したら、分散キーで指定されているキー値を格納する要素IDまたはレプリカ・セットIDを取得するのにTimesTenDistributionKeyインタフェースのgetElementIDsまたはgetReplicaSetIDメソッドを使用します。


注意:

TimesTen Scaleoutの場合、TimesTenDataSourceクラスに接続および分散キーのファクトリ・メソッドが実装されています。

例2-23 要素IDおよびレプリカ・セットIDの取得

この例では、単一列の分散キーのキー値の要素IDおよびレプリカ・セットIDを計算して出力します。

import java.sql.SQLException;
import java.sql.Types;
 
import com.timesten.jdbc.TimesTenDataSource;
import com.timesten.jdbc.TimesTenDistributionKey;
import com.timesten.jdbc.TimesTenDistributionKeyBuilder;

public class ClientRouting {
 
   public static void main(String[] args) {
 
      try {
 
         /* Establish a connection to an element of the database. Maintain this 
          * connection for the duration of the application for computing element 
          * IDs and creating connections. */
         TimesTenDataSource ds = new TimesTenDataSource();
         ds.setUrl("jdbc:timesten:client:database1");
         ds.setUser("terry");
         ds.setPassword("password");
 
         /* Build a distribution key. The distribution key is composed of a single
          * TT_INTEGER column. */
         TimesTenDistributionKey dk = ds.createTimesTenDistributionKeyBuilder()
               .subkey(3, Types.INTEGER)
               .build();
 
         // Get the element IDs for the distribution key.
         short[] elementIDs = dk.getElementIDs();
 
         for (short id : elementIDs) {
            System.out.println("Distribution key(3), element ID: " + id);
         }
 
         // Get the replica set ID for the disitribution key.
         System.out.println("Distribution key(3), replica set ID: " +
 dk.getReplicaSetID());
 
      } catch (SQLException ex) {         ...      }
   }
}

このコード・スニペットでは、複数の列で構成される分散キーのキー値のセットの要素IDおよびレプリカ・セットIDを計算して出力します。

...
/* Build a distribution key. The distribuion key is composed of two columns -- 
 * one TT_INTEGER and one VARCHAR2. */
dk = ds.createTimesTenDistributionKeyBuilder()
      .subkey(1, Types.INTEGER)
      .subkey("john.doe", Types.VARCHAR)
      .build();
 
// Get the element IDs for the distribution key
elementIDs = dk.getElementIDs();
for (short id : elementIDs) {
   System.out.println("Distribution key(1, john.doe), element ID: " + id);
}
// Get the replica set ID for the distribution key.
System.out.println("Distribution key(1, john.doe), replica set ID: " +
 dk.getReplicaSetID());
...

分散キーに基づく要素への接続

クライアント・アプリケーションは、TimesTen Scaleoutのデータベースの特定要素に接続するのに任意のカスタム・メソッドを使用できます。ただし、TimesTenConnectionBuilderインタフェースで指定されている機能では、分散キー、要素IDまたはレプリカ・セットIDに基づく最適な要素へのアプリケーションの接続を可能にします。

例2-24 分散キーに基づく要素への接続

この例では、分散キーを作成し、それにより接続を作成します。

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
 
import com.timesten.jdbc.TimesTenDataSource;
import com.timesten.jdbc.TimesTenDistributionKey;
import com.timesten.jdbc.TimesTenDistributionKeyBuilder;
 
public class ClientRouting {
 
   public static void main(String[] args) {
 
      try {
 
         // Create and mantain connection to database.
         TimesTenDataSource ds = new TimesTenDataSource();
         ds.setUrl("jdbc:timesten:client:database1");
         ds.setUser("terry");
         ds.setPassword("password");
 
         // Build a distribution key.
         TimesTenDistributionKey dk = ds.createTimesTenDistributionKeyBuilder()
               .subkey(1, Types.INTEGER)
               .subkey("john.doe", Types.VARCHAR)
               .build();
 
         // Connect to optimal element based on a distribuion key.
         Connection conn;
         conn = ds.createTimesTenConnectionBuilder()
               .user("terry")
               .password("password")
               .distributionKey(dk)
               .build();
         Statement stmt = conn.createStatement();
         stmt.execute("... SQL statement here ...");
         stmt.close();
         conn.close();
 
      } catch (SQLException ex) {
         ...
      }
   }
}

このコード・スニペットでは、要素IDに基づいて接続を作成します。

...
// Connect to optimal element based on an element ID.
short[] elementIDs = dk.getElementIDs();
conn = ds.createTimesTenConnectionBuilder()
      .user("terry")
      .password("password")
      .elementID(elementIDs[0])
      .build();
Statement stmt = conn.createStatement();
stmt.execute("... SQL statement here ...");
stmt.close();
conn.close();
...
 

このコード・スニペットでは、レプリカ・セットIDに基づいて接続を作成します。

...
// Connect to optimal element based on a replica set ID.
short repSetID = dk.getReplicaSetID();
conn = ds.createTimesTenConnectionBuilder()
      .user("terry")
      .password("password")
      .replicaSetID(repSetID)
      .build();
Statement stmt = conn.createStatement();
stmt.execute("... SQL statement here ...");
stmt.close();
conn.close();
...

サポートされるデータ型

表2-5に、サポートされているデータ型および使用可能なオブジェクト・タイプを示します。最高のパフォーマンスが得られるように、推奨されるオブジェクト型を使用して型の変換を回避してください。

表2-5 サポートされているデータ型および使用可能なオブジェクト・タイプ

SQLの型 java.sql.Types 推奨されるオブジェクト・クラス 使用可能なオブジェクト・クラス

TT_TINYINT

Types.TINYINT

Short

ByteShort

TT_SMALLINT

Types.SMALLINT

Short

ByteShort

TT_INTEGER

Types.INTEGER

Integer

ByteShortInteger

TT_BIGINT

Types.BIGINT

Long

ByteShortIntegerLong

CHAR

Types.CHAR

String

String

NCHAR

Types.NCHAR

String

String

VARCHAR2

Types.VARCHAR

String

String

NVARCHAR

Types.NCHAR

String

String

NUMBER

Types.DECIMAL

TYPES.NUMERIC

BigDecimal

BigDecimal

toString()メソッドは他のクラスに対して実行されます。


制限事項

TimesTen Scaleoutのクライアント・ルーティングのJDBC拡張については、Oracle TimesTen In-Memory Database C開発者ガイドのTimesTen Scaleoutのクライアント・ルーティングAPIにリストされているのと同じ制限が当てはまります。