ヘッダーをスキップ
Oracle® TimesTen In-Memory Database Java開発者ガイド
11gリリース2 (11.2.2)
B66445-06
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

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

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

前提条件タスク 実行内容
データベースの作成。 『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTenデータベースの管理に関する手順に従います。
Java環境の構成。 「Java開発環境の構成」の手順に従います。
TimesTen Javaのデモのコンパイルおよび実行。 「TimesTen Javaのデモ」の手順に従います。

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

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

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

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

標準JDBCの詳細は、java.sqlパッケージに関する次の情報を参照してください(1つ目はJava 6用、2つ目はJava 5.0用)。

http://docs.oracle.com/javase/6/docs/api/java/sql/package-summary.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/package-summary.html

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


注意:

TimesTenではJava 6を使用することを推奨します。Java 6のAPIは、特にLOBの操作においてより機能があります。

パッケージのインポート

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()メソッドはサポートされていません。

  • Java 5.0ではfree()またはgetBinaryStream(pos,length)はサポートされていませんが、TimesTenでは拡張として提供されています。これらはJava 6では標準です。

CallableStatement

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

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

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

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

Clob

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

  • Java 5.0ではfree()またはgetCharacterStream(pos,length)をサポートしていませんが、TimesTenでは拡張として提供されています。これらはJava 6では標準です。

Connection

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

DatabaseMetaData

  • 制限はありません。

NClob

  • NClobは、Java 6のみでサポートされています(ttjdbc6.jar)。

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

ParameterMetaData

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

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

PreparedStatement

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

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

  • 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は、Java 6のみでサポートされています(ttjdbc6.jar)。

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

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

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

Statement

  • 制限はありません。

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

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


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

TimesTenでは、次のjava.sqlクラスをサポートしています。

  • DataTruncation

  • Date

  • DriverManager

  • DriverPropertyInfo

  • Time

  • Timestamp

  • Types

  • SQLException

  • SQLWarning

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

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

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

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

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

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


重要:

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

サンプルのTimesTen接続プール・パッケージはクイック・スタート・デモの一部として提供されています。これは、次のディレクトリにあります。

install_dir/quickstart/sample_code/jdbc/connectionpool

TimesTenでは、次のjavax.sqlイベントおよびリスナーをサポートしています。

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


注意:

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

TimesTen JDBC拡張

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

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

表2-2 TimesTen JDBC拡張

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

TimesTenBlob

Blob

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

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

TimesTenCallableStatement

CallableStatement

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

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

TimesTenClob

Clob

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

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

TimesTenConnection

Connection

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

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

Java 5.0用にファクトリ・メソッドcreateBLOB()およびcreateCLOB()を提供します。(LOBファクトリ・メソッドはJava 5.0にはありません。)「LOBの作業」を参照してください。

TimesTenNClob

NClob

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

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

TimesTenPreparedStatement

PreparedStatement

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

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

TimesTenStatement

Statement

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


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

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

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

  • REF CURSORのためのTimesTen型の拡張に、TimesTenTypesを使用します。

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

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

その他のTimesTenクラス

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

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

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

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

この項で説明する操作は、level1デモに基づいています。「TimesTen Javaのデモ」を参照してください。

ここでは次の内容について説明します。


注意:

TimesTenドライバのロード(Java 5.0):

TimesTenではJava 6を使用することを推奨します。ただし、Java 5.0を使用する場合は、データベース接続の作成に利用できるようTimesTenドライバを明示的にロードする必要があります(しない場合、アプリケーションが接続を試行する際、TimesTenによってエラーが返されます)。この手順は、Java 6では不要です。

次に、(直接接続用とクライアント/サーバー接続用の)TimesTen JDBCドライバを示します。

com.timesten.jdbc.TimesTenDriver
com.timesten.jdbc.TimesTenClientDriver

Java 5.0でTimesTenへの接続にDriverManagerインタフェースを使用する場合、Class.forName()メソッドをコールして、TimesTen JDBCドライバをロードします。このメソッドによって、TimesTenドライバのインスタンスが作成され、ドライバ・マネージャに登録されます。TimesTenDataSourceインタフェースを使用している場合、Class.forName()をコールする必要はありません。

TimesTen直接ドライバを特定およびロードする例を次に示します。

Class.forName("com.timesten.jdbc.TimesTenDriver");

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

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

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

デフォルトはdirectです。

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

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

接続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_1122;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(myttpwd);                     // Password to log in to TimesTen
ds.setUrl("jdbc:timesten:direct:<dsn>");
ds.setOraclePassword(myorapwd);              // 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 Javaのデモ」を参照してください。

データベースからの切断

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

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

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

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

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

String URL = "jdbc:timesten:dsn=sampledb_1122";
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が返されます。

接続のアクセス制御

任意のユーザー(インスタンス管理者以外)がデータベースに接続するには、CREATE SESSION権限を付与する必要があります。これはシステム権限であるため、インスタンス管理者、またはADMIN権限を持った者からユーザーに対して、直接またはPUBLICロールを介して付与する必要があります。詳細な説明および例については、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のアクセス制御の管理に関する項を参照してください。

JMS/XLA接続を作成し、JMS/XLAの機能を実行するには、CREATE SESSION権限に加え、「アクセス制御がXLAに与える影響」で説明するXLA権限をユーザーに付与する必要があります。

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文の実行時など)結果セットが必要な場合にのみコールする必要があります。


注意:


例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()を使用して、処理後すぐに結果セットをクローズできます。パフォーマンス上の理由から、これは読取りおよび更新処理で使用される結果セットおよびプール接続で使用される結果セットで特に重要です。

  • 基礎となるデータ型が文字列ではない場合、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()をコールして、現行のプリフェッチ値を確認します。

詳細は、『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();

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

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


注意:

  • StatementPreparedStatementまたはCallableStatementのメソッドclose()を使用して、使用が終わった文をクローズします。

  • 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()よりもパフォーマンスに優れています。

  • アクセス制御権限は、SQLが準備されたとき、およびそのSQL文がデータベースで実行されたときに確認されます。関連する情報は、「アクセス制御のためのTimesTen機能の検討」を参照してください。

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

例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 Javaのデモ」を参照してください。)

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're 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では、SQL文で重複したパラメータをバインドするための2つの異なるモードをサポートしています。

  • Oracleモード: 同じパラメータ名の複数のインスタンスは別のパラメータとして認識されます。

  • 以前のリリースと同様の従来のTimesTenモード: 同じパラメータ名が複数回出現する場合、同じパラメータが複数回出現しているとみなされます。

DuplicateBindMode TimesTen一般接続属性を使用すると、目的のモードを選択できます。DuplicateBindMode=0(デフォルト)はOracleモードで、 DuplicateBindMode=1はTimesTenモードです。この属性は一般接続属性であるため、同じデータベースに対する複数の接続でそれぞれ異なる値を使用できます。この属性の詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のDuplicateBindModeに関する項を参照してください。

この項の後半では、各モードの詳細を示します。次の問合せについて考えてみます。

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

注意:

この説明は、(PL/SQLなどを介してではなく)JDBCから直接発行されたSQL文にのみ該当します。

重複パラメータに対するOracleモード

Oracleモード(DuplicateBindMode=0)では、1つのSQL文に含まれる同じパラメータ名の複数回の出現は異なるパラメータとみなされます。パラメータ位置番号を割り当てるとき、名前の重複は考慮せずに各パラメータの出現に番号が割り当てられます。アプリケーションでは、最低でも、各パラメータ名の最初の出現に値がバインドされます。そのパラメータ名が次回出現した場合、アプリケーションでは次のいずれかが実行されます。

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

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

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

前述の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にあるとみなされます。

重複パラメータに対するTimesTenモード

TimesTenモード(DuplicateBindMode=1)では、重複したパラメータを含むSQL文は、異なるパラメータ名のみが別のパラメータとしてみなされるように解析されます。アプリケーションでは一意のパラメータごとにのみ1つの値がバインドされ、一意でないパラメータはバインドされません。

バインドは、パラメータ名が最初に出現した位置に基づいて行われます。以降に出現するパラメータ名は、同じ値にバインドされ、パラメータ位置番号は与えられません。

前述のSQL文では、aの2つの出現が単一のパラメータとみなされるため、別々にバインドすることはできません。

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

TimesTenモードでは、パラメータbは位置3ではなく、位置2にあるとみなされることに注意してください。

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-3を参照してください。

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

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

表2-3 連想配列要素の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をアプリケーションに渡して結果セットを処理することができます。

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

  1. TimesTenTypes.CURSOR(TimesTen型拡張)としてREF CURSOR OUTパラメータを登録すると、REF CURSORのパラメータ位置(文内の位置)も指定されます。

  2. TimesTenCallableStatementインタフェース(TimesTen JDBC拡張の1つ)で定義されたgetCursor()メソッドを使用してREF CURSORを取得し、REF CURSORのパラメータ位置を指定します。getCursor()メソッドは他のgetXXX()メソッドと同様に使用され、ResultSetインスタンスを返します。

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からアプリケーションへのOUT REF CURSORのみと、REF CURSORを1つのみ返す文をサポートしています。

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

例2-11 REF CURSORの使用

この例は、コール可能な文でのREF CURSORの使用方法を示します。PL/SQLブロックは、CallableStatementインスタンスでカーソルをオープンし、問合せを実行します。TimesTenCallableStatementメソッドgetCursor()は、カーソルを戻すために使用され、そのカーソルはTimesTenTypes.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();
...

注意:

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

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 6用に、java.sql.RowIdインタフェースとTypes.ROWID型をサポートしています。

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

  • byte[] getBytes(int columnIndex)

  • String getString(int columnIndex)

  • Object getObject(int columnIndex)

    Java 5.0では、Stringオブジェクトが返されます。Java 6では、RowIdオブジェクトが返されます。

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

  • setBytes(int parameterIndex, byte[] x)

  • setString(int parameterIndex, String x)

  • setRowId(int parameterIndex, RowId x)(Java 6のみ)

  • setObject(int parameterIndex, Object x)

    Java 5.0では、Stringオブジェクトを取ります。Java 6では、StringまたはRowIdオブジェクトを取ります。


注意:

getBytes()またはsetBytes()を、PL/SQLパラメータまたはパススルー・パラメータ(TimesTen Application-Tier Database Cacheの使用時にOracle Databaseに渡すパラメータ)になるROWIDパラメータに使用できません。RowIdオブジェクト(Java 6のみ)またはStringオブジェクトには、getString()およびsetString()またはgetObject()およびsetObject()を使用してください。

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

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


注意:

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

LOBの作業

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

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


注意:

  • データベースのキャラクタ・セットがTIMESTEN8の場合、TimesTenではCLOBをサポートしません。

  • この項では、Java 5.0およびJava 6の両方におけるLOBのサポートについて説明します。ただし、TimesTenではJava 6を使用することを推奨します。こちらの方がより標準的で、完全な実装となります。具体的には、Java 5.0ではNCLOBをサポートしていません。


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

  • 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オブジェクトは無効になります。これには、Oracle Databaseの動作での、あらゆる自動コミット後、またはTimesTenのDDLCommitBehaviorが0(デフォルト)に設定されている場合のあらゆるDDL文後も含まれます。

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

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

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

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

LOBファクトリ・メソッド

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

標準のLOBファクトリ・メソッドがないJava 5.0環境(非推奨)では、TimesTenの拡張のTimesTenConnectionインタフェースにより、次が規定されています。

  • createBLOB()

  • createCLOB()

Java 5.0では、NCLOBをサポートしていません。

詳細は、『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()メソッド(Java 6のみ)があります。

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

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

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

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

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

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

    BlobClobまたはNClob(Java 6のみ)出力パラメータを取得する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リソースを解放します。

    注意: free()メソッドはJava 5.0には含まれませんが、TimesTenの拡張として提供されます。これはJava 6では標準です。

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

    注意: getBinaryStream(pos,length)シグネチャはJava 5.0には含まれませんが、TimesTenの拡張として提供されます。これはJava 6では標準です。

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

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

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

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

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

ClobおよびNClob(Java 6のみ)の機能の概要は、次のとおりです。

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

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

    注意: free()メソッドはJava 5.0には含まれませんが、TimesTenの拡張として提供されます。これはJava 6では標準です。

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

    注意: getCharacterStream(pos,length)シグネチャはJava 5.0には含まれませんが、TimesTenの拡張として提供されます。これはJava 6では標準です。

  • 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".

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

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

myconn.commit();

または

myconn.rollback();

COMMIT文およびROLLBACK SQL文の使用

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

mystmt.execute("COMMIT");

複数スレッドの管理


注意:

一部のUNIXプラットフォームでは、THREADS_FLAGを『Oracle TimesTen In-Memory Databaseインストレーション・ガイド』のTHREADS_FLAG変数の設定に関する説明に従って設定する必要があります。

level4デモでは、複数スレッドの使用について説明します。「TimesTen Javaのデモ」を参照してください。

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

各スレッドに割り当てられるスタック空間の量は、スレッドの作成時にオペレーティング・システムが指定します。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()のコールで使用できます。

前者では、タイムアウト期間になると文の実行が停止しエラーがスローされる、タイムアウトを設定します。後者では、しきい値に達すると、SNMPトラップがスローされますが実行は継続される、しきい値を設定します。

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

TimesTenでは、SqlQueryTimeout一般接続属性を設定して、接続(つまり、接続の任意の文)に対してタイムアウト期間(秒)を指定できます。(『Oracle TimesTen In-Memory Databaseリファレンス』のSqlQueryTimeoutに関する説明も参照してください。)値0はタイムアウトが発生しないことを示します。名前に反して、このタイムアウト値は問合せだけでなく、実行可能な任意のSQL文に適用されます。

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

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


注意:

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

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

SQL文の実行時間が、指定した期間(秒)を超えたときに、サポート・ログに警告を書き込み、SNMPトラップをスローするように、TimesTenを構成できます。実行は継続され、しきい値の影響は受けません。

SNMPトラップの名前は、ttQueryThresholdWarnTrapです。SNMPトラップの構成に関する情報は、『Oracle TimesTen In-Memory Databaseエラー・メッセージおよびSNMPトラップ』を参照してください。

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

デフォルトでは、アプリケーションはしきい値をQueryThreshold一般接続属性設定から取得します。データベースの接続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 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ユーザーズ・ガイド』のパススルー・レベルの設定に関する説明を参照してください。

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

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

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

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

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

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

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

  • ユーザー定義のパラレル・レプリケーション()ReplicationApplyOrdering=1: クラシック・レプリケーション・スキームを使用し、トランザクションの依存性の予測性が高く、レシーバでのコミット順序が元のデータベース上のコミット順序と同じである必要がないアプリケーションの場合。トランザクションの追跡数を指定し、各追跡に特定のトランザクションを適用できます。すべての追跡の読取り、送信および適用はパラレルに行われます。

詳細および使用方法のシナリオについては、『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機能の検討

TimesTenには、データベース・オブジェクト(表、ビュー、マテリアライズド・ビュー、順序およびシノニムなど)をオブジェクト・レベルで分解することによる、データベース・アクセス制御の機能があります。TimesTenアクセス制御の概要については、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のアクセス制御の管理に関する項を参照してください。

この項では、SQL操作、データベース接続およびJMS/XLAに関連するアクセス制御について説明します。

このマニュアルで説明されている、または例で使用されている問合せ、SQL DMLまたはDDL文では、ユーザーは、その文の実行のために適切な権限を持っていることを前提としています。たとえば、表に対するSELECT文では、その表の所有権、その表に関して付与されているSELECT権限またはSELECT ANY TABLEシステム権限が必要です。同様に、DML文にはその表の所有権、その表に関して付与されている適切なDML権限(UPDATEなど)または適切なANY TABLE権限(UPDATE ANY TABLEなど)が必要です。

DDL文の場合、CREATE TABLEにはユーザー・スキーマのCREATE TABLE権限またはその他のスキーマのCREATE ANY TABLE権限が必要です。ALTER TABLEは、所有権またはALTER ANY TABLEシステム権限を必要とします。DROP TABLEは、所有権またはDROP ANY TABLEシステム権限を必要とします。オブジェクト・レベルのALTER権限またはDROP権限はありません。

アクセス制御権限のリストおよび与えられたSQL文に必要な権限については、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のSQL文に関する項を参照してください。

権限は、SQLのGRANT文で付与され、REVOKE文で取り消されます。一部の権限は、すべてのユーザーがメンバーになっているPUBLICロールによって自動的にすべてのユーザーに付与されます。このロールに関する情報は、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のPUBLICロールに関する項を参照してください。

また、アクセス制御は、このマニュアルで説明している次の内容に関係します。


注意:

  • アクセス制御を無効にすることはできません。

  • アクセス制御権限は、SQLの準備時およびそのSQL文のデータベースでの実行時の両方で確認され、大部分のパフォーマンス・コストは準備時に発生します。


エラー処理

この項では、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のデモでは、デモ・スキーマをロードしてから実行する必要があります。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);
}

SYS.MONITOR表のXACT_ROLLBACKS列は、ロールバックされたトランザクションの数を示します。詳細は、『Oracle TimesTen In-Memory Databaseシステム表およびビュー・リファレンス』のSYS.MONITORに関する説明を参照してください。

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


注意:

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

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

自動クライアント・フェイルオーバーは、レプリケーションが構成されたTimesTenのアクティブなスタンバイ・ペアにおける高可用性のシナリオで使用します。アクティブ・ノードに障害があると、新しいアクティブ(元のスタンバイ)・ノードへのフェイルオーバー(転送)が発生し、アプリケーションは新しいアクティブ・ノードに自動的に再接続されます。TimesTenは自動クライアント・フェイルオーバーが発生したときに、アプリケーションに警告を渡す機能を提供しているため、アプリケーションは適切な処理を行うことができます。

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


注意:

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

Oracle Clusterwareを使用する場合、自動クライアント・フェイルオーバーはOracle Clusterwareに対する補完機能ですが、この2つの機能は互いに依存しません。

自動クライアント・フェイルオーバーの一般情報は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の自動クライアント・フェイルオーバーの使用に関する説明を、開発者向けの関連情報は、『Oracle TimesTen In-Memory Database C開発者ガイド』のアプリケーションでの自動クライアント・フェイルオーバーの使用に関する説明を参照してください。

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のインスタンスの実装および登録を行いません。

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

詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の自動クライアント・フェイルオーバーの構成に関する説明を参照してください。


注意:

TTC_Server2TTC_Server_DSN2またはTCP_Port2のいずれかを設定することは、暗黙的に次のことを意味します。
  • ユーザーは、自動クライアント・フェイルオーバーを使用するつもりである。

  • ユーザーは、フェイルオーバー・メカニズムをサポートするためにアプリケーションに新しいスレッドが作成されることを理解している。

  • アプリケーションをスレッド・ライブラリにリンクしました(UNIXシステムでのpthread)。


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

フェイルオーバー時に、障害が発生した接続に作成されたオブジェクトをアプリケーションで使用しようとすると、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)

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