Database JDBC開発者ガイド

11gリリース2(11.2)

B56281-02(原本部品番号:E16548-03)

目次

例一覧

図一覧

表一覧

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

新機能

- リリース2(11.2)の新機能

第I部 概要

1 JDBCの概要

- Oracle JDBCドライバの概要

- Oracle JDBCドライバの共通機能

- 適切なドライバの選択

- JDBC OCIドライバとJDBC Thinドライバの機能の相違点

- 環境およびサポート

- サポートされるJDKおよびJDBCのバージョン

- JNI環境およびJava環境

- JDBCとIDE

- 機能リスト

2 スタート・ガイド

- Oracle JDBCドライバのバージョン互換性

- JDBCクライアント・インストールの検証

- インストールされたディレクトリとファイルの確認

- 環境変数の確認

- Javaコードのコンパイルと実行の確認

- JDBCドライバのバージョンの確認

- JDBCおよびデータベース接続のテスト

- JDBCでの基本的な処理

- パッケージのインポート

- データベースへの接続のオープン

- Statementオブジェクトの作成

- 問合せの実行と結果セット・オブジェクトの取出し

- 結果セット・オブジェクトの処理

- 結果セット・オブジェクトとStatementオブジェクトのクローズ

- データベースの変更

- 変更のコミット

- コミット動作の変更

- 接続のクローズ

- サンプル: 接続、問合せおよび結果処理

- JDBCプログラムでのストアド・プロシージャ・コール

- PL/SQLストアド・プロシージャ

- Javaストアド・プロシージャ

- SQL例外の処理

第II部 Oracle JDBC

3 JDBC標準のサポート

- JDBC 2.0標準のサポート

- データ型のサポート

- 標準機能のサポート

- 拡張機能のサポート

- JDBC2.0 Standard Extension APIとオラクル社独自のパフォーマンス強化API

- JDBC 3.0標準のサポート

- トランザクション・セーブポイント

- セーブポイントの作成

- セーブポイントまでのロールバック

- セーブポイントの解放

- セーブポイント・サポートのチェック

- セーブポイントに関する注意事項

- 自動生成キーの取出し

- java.sql.Statement

- サンプル・コード

- 制限事項

- JDBC 3.0のLOBインタフェース・メソッド

- 結果セットの保持機能

- JDBC 4.0標準のサポート

- ラッパー・パターンのサポート

- SQLXML型

- 機能拡張された例外階層とSQLException

- ROWIDデータ型

- LOBの作成

- 各国語キャラクタ・セットのサポート

4 Oracle拡張機能

- Oracle拡張機能の概要

- Oracle拡張機能

- JDBCを使用したデータベース管理

- Oracleデータ型のサポート

- Oracleオブジェクトのサポート

- スキーマの命名サポート

- DML RETURNING

- PL/SQL索引付き表へのアクセス

- Oracle JDBCパッケージ

- パッケージoracle.sql

- パッケージoracle.jdbc

- Oracle文字データ型のサポート

- SQL CHARデータ型

- SQL NCHARデータ型

- クラスoracle.sql.CHAR

- その他のOracle型拡張機能

- Oracle ROWID型

- Oracle REF CURSOR型カテゴリ

- Oracle BINARY_FLOAT型およびBINARY_DOUBLE型

- Oracle SYS.ANYTYPE型およびSYS.ANYDATA型

- oracle.jdbcパッケージ

- インタフェースoracle.jdbc.OracleConnection

- インタフェースoracle.jdbc.OracleStatement

- インタフェースoracle.jdbc.OraclePreparedStatement

- インタフェースoracle.jdbc.OracleCallableStatement

- インタフェースoracle.jdbc.OracleResultSet

- インタフェースoracle.jdbc.OracleResultSetMetaData

- クラスoracle.jdbc.OracleTypes

- メソッドgetJavaSqlConnection

- DML RETURNING

- Oracle固有のAPI

- DML RETURNING文の実行

- DML RETURNINGの例

- DML RETURNINGの制限事項

- PL/SQL索引付き表へのアクセス

- 概要

- INパラメータのバインド

- OUTパラメータの受取り

- 型マッピング

5 JDBC Thin固有の機能

- JDBC Thinクライアントの概要

- サポートする追加機能

- アプレットのサポート

- ネイティブXAのデフォルトでのサポート

- アプレット内のJDBC

- アプレットを介したデータベースへの接続

- Webサーバーとは異なるホスト上のデータベースへの接続

- Oracle Connection Managerの使用

- 署名付きアプレットの使用

- ファイアウォールとアプレットの使用方法

- JDBC Thinドライバを使用するアプレット用のファイアウォールの構成

- ファイアウォールを通過する接続のためのURLの記述

- アプレットのパッケージ化

- HTMLページでのアプレットの指定

- CODE、HEIGHTおよびWIDTH

- CODEBASE

- ARCHIVE

6 JDBC OCIドライバ固有の機能

- OCI接続プーリング

- クライアント結果キャッシュ

- クライアント結果キャッシュの利点

- JDBCでの使用ガイドライン

- RESULT_CACHE_MODEパラメータ

- 表注釈

- SQLヒント

- 透過的アプリケーション・フェイルオーバー

- OCIネイティブXA

- OCI Instant Client

- Instant Clientの概要

- Instant Clientの利点

- JDBC OCI Instant Clientのインストール手順

- Instant Clientの使用

- Instant Client共有ライブラリのパッチ

- データ共有ライブラリとZIPファイルの再生成

- OCI Instant Client用のデータベース接続名

- OCI Instant Clientの環境変数

- Instant Client Light(English)

- グローバリゼーション設定

- 動作

- インストール

7 サーバー側内部ドライバ

- サーバー側内部ドライバの概要

- データベースへの接続

- セッション・コンテキストおよびトランザクション・コンテキスト

- サーバー上でのJDBCのテスト

- サーバーへのアプリケーションのロード

- loadjavaユーティリティの使用

- JVMコマンドラインの使用

第III部 接続とセキュリティ

8 データソースおよびURL

- データソース

- JNDIのOracleデータソース・サポートの概要

- データソースの機能とプロパティ

- データソース・インスタンスの作成と接続

- データソース・インスタンスの作成、JNDIへの登録および接続

- サポートされている接続プロパティ

- SYSログインのためのロールの使用方法

- データベース・リモート・ログインの構成

- Bequeathed接続とSYSログオン

- Oracleパフォーマンス拡張要素のプロパティ

- データベースURLとデータベース指定子

9 JDBCクライアント側セキュリティ機能

- Oracle Advanced Securityのサポート

- ログイン認証のサポート

- 厳密認証のサポート

- OS認証のサポート

- Linuxの構成手順

- Windowsの構成手順

- OS認証を使用するJDBCコード

- データ暗号化と整合性のサポート

- JDBC OCIドライバによるデータ暗号化と整合性のサポート

- JDBC Thinドライバによるデータ暗号化と整合性のサポート

- Javaでの暗号化および整合性パラメータの設定

- SSLのサポート

- 証明書とウォレットの管理

- 鍵と証明書のコンテナ

- Kerberosのサポート

- Kerberosを使用するためのWindowsの構成

- Kerberosを使用するためのOracle Databaseの構成

- サンプル・コード

- RADIUSのサポート

- RADIUSを使用するためのOracle Databaseの構成

- サンプル・コード

- セキュアな外部パスワード記憶域

10 プロキシ認証

- プロキシ認証について

- 各種のプロキシ接続

- プロキシ接続の作成

- プロキシ・セッションのクローズ

- プロキシ接続のキャッシュ

- プロキシ接続の制限

第IV部 データへのアクセスと操作

11 Oracleデータへのアクセスと操作

- データ型マッピング

- マッピングの表

- マッピングに関する注意

- データ変換での考慮事項

- 標準型とOracle型

- SQL NULLデータの変換

- NULLのテスト

- 結果セットと文拡張機能

- Oracleのgetおよびsetメソッドと標準JDBCの比較

- 標準getObjectメソッド

- Oracle getOracleObjectメソッド

- getObjectおよびgetOracleObject戻り型のまとめ

- その他のgetXXXメソッド

- getXXXメソッドの戻り型

- getXXXメソッドに関する特別な注意

- getObjectおよびgetXXXから戻されるオブジェクトのデータ型

- setObjectメソッドとsetOracleObjectメソッド

- その他のsetXXXメソッド

- 入力データのバインド

- WHERE句にCHARデータをバインドするためのメソッドsetFixedCHAR

- 結果セット・メタデータ拡張機能の使用方法

- SQL CALL文とCALL INTO文の使用

12 JDBC内のJavaストリーム

- Javaストリームの概要

- LONGまたはLONG RAW列のストリーム

- LONG RAWデータの変換

- LONGデータの変換

- LONG RAWデータのストリーム例

- LONGまたはLONG RAWのストリーム回避

- CHAR、VARCHARまたはRAW列のストリーム

- LOBおよび外部ファイルのストリーム

- データ・ストリームと複数列

- ストリームのクローズ

- ストリームに関する注意

- ストリーム・データを使用する際の注意

- setBytesとsetStringの制限を回避するためのストリームの使用方法

- ストリームと行のプリフェッチ

13 Oracleオブジェクト型の操作

- Oracleオブジェクトのマッピング

- Oracleオブジェクト用のデフォルトSTRUCTクラスの使用方法

- STRUCTクラス機能

- STRUCTオブジェクトと属性の取出し

- STRUCTオブジェクトの作成

- STRUCTオブジェクトの文へのバインド

- STRUCT自動属性バッファリング

- Oracleオブジェクト用のカスタム・オブジェクト・クラスの作成と使用方法

- ORADataとSQLDataの利点

- SQLDataを実装するための型マップ

- 型マップの作成とSQLData実装のマッピング定義

- 既存の型マップへのエントリの追加

- 新しい型マップの作成

- 型マップで指定されていないオブジェクト型のインスタンス化

- SQLData実装によるデータの読取りおよび書込み

- ORADataインタフェース

- ORAData実装によるデータの読取りおよび書込み

- その他のORADataの使用方法

- オブジェクト型の継承

- サブタイプの作成

- サブタイプに対してカスタマイズされたクラスの実装

- ORADataを使用した型継承階層の作成

- SQLDataを使用した型継承階層の作成

- JPublisherユーティリティ

- サブタイプ・オブジェクトの取得

- サブタイプ・オブジェクトの作成

- サブタイプ・オブジェクトの送信

- サブタイプ・データ・フィールドへのアクセス

- 継承メタデータ・メソッド

- JPublisherを使用したカスタム・オブジェクト・クラスの作成

- JPublisherの機能

- JPublisher型マッピング

- オブジェクト型の記述

- オブジェクト・メタデータの取出し機能

- オブジェクト・メタデータを取り出す手順

14 LOBとBFILEの操作

- LOBデータ型

- Oracle SecureFile

- LOBのデータ・インタフェース

- 効率的なメカニズム

- 入力

- 出力

- CallableSatementとIN OUTパラメータ

- サイズの制限

- LOBロケータ・インタフェース

- 一時LOBの使用

- OpenおよびCloseメソッドによる通常のLOBのオープン

- BFILEの操作

15 Oracleオブジェクト参照の使用

- オブジェクト参照用Oracle拡張機能

- オブジェクト参照の取出しと引渡し

- 結果セットからのオブジェクト参照の取出し

- オブジェクト参照のコール可能文からの取出し

- オブジェクト参照のプリコンパイルされたSQL文への引渡し

- オブジェクト値に対する、オブジェクト参照を介したアクセスと更新

- JPublisherで生成するカスタム参照クラス

16 Oracleコレクションの操作

- コレクションのためのOracle拡張機能

- コレクションのインスタンス化に関する選択

- コレクションの作成

- マルチ・レベルのコレクション型の作成

- コレクション機能の概要

- ARRAYパフォーマンス拡張要素メソッド

- Javaプリミティブ型の配列としてのoracle.sql.ARRAY要素へのアクセス

- ARRAY自動要素バッファリング

- ARRAY自動索引作成

- 配列の作成と使用方法

- ARRAYオブジェクトの作成

- 配列とその要素の取出し

- 配列の取出し

- データ取出しメソッド

- データ取出しメソッドの比較

- 型マップに従った構造化オブジェクト配列の要素の取出し

- 配列要素のサブセットの取出し

- oracle.sql.Datum配列への配列要素の取出し

- マルチ・レベル・コレクション要素へのアクセス

- 配列の文オブジェクトへの引渡し

- 型マップを使用した配列要素のマップ

- JPublisherで生成するカスタム・コレクション・クラス

17 結果セット

- 結果セットのサポートのOracle JDBC実装概要

- 結果セットの制限事項およびダウングレード・ルール

- 更新の競合回避

- フェッチ・サイズ

- フェッチ・サイズの設定

- フェッチ方向のプリセット

- 行の再フェッチ

- 内部的および外部的に加えられたデータベース変更の参照

- 外部変更の可視性と検出

- 内部変更および外部変更の可視性の概要

- Scroll-Sensitive結果セットのOracle実装

18 JDBC RowSet

- JDBC RowSetの概要

- RowSetのプロパティ

- イベントおよびイベント・リスナー

- コマンド・パラメータおよびコマンド実行

- RowSetの横断

- CachedRowSet

- JdbcRowSet

- WebRowSet

- FilteredRowSet

- JoinRowSet

19 グローバリゼーション・サポート

- グローバリゼーション・サポートの提供

- JDK 1.5のNCHAR、NVARCHAR2、NCLOBおよびdefaultNCharプロパティ

- JDK 1.6での各国語キャラクタ・セット用の新しいメソッド

第V部 パフォーマンスとスケーラビリティ

20 文キャッシュと結果セット・キャッシュ

- 文キャッシュについて

- 文キャッシュの基本

- 暗黙的文キャッシュ

- 明示的文キャッシュ

- 文キャッシュの使用方法

- 文キャッシュの有効化および無効化

- キャッシュされた文のクローズ

- 暗黙的文キャッシュの使用方法

- 明示的文キャッシュの使用方法

- 文オブジェクトの再利用

- プールされた文の使用

- プールされた文のクローズ

- 結果セット・キャッシュ

- サーバー側キャッシュ

- クライアント結果キャッシュ

21 暗黙的接続キャッシュ

- 暗黙的接続キャッシュ

- 接続キャッシュの使用

- キャッシュの有効化

- 接続のオープン

- 接続キャッシュ名の設定

- 接続キャッシュ・プロパティの設定

- 接続のクローズ

- 暗黙的接続キャッシュの例

- 接続属性

- 接続の取得

- 接続属性の設定

- 戻された接続の属性の確認

- 接続属性の例

- 接続キャッシュ・プロパティ

- 制限プロパティ

- タイムアウト・プロパティ

- その他のプロパティ

- 接続プロパティの例

- Connection Cache Manager API

- 高度なトピック

- 属性の重みと接続の一致

- 接続キャッシュのコールバック

- TimeToLiveTimeoutおよびAbandonedConnectionTimeoutのユースケース

22 実行時接続ロード・バランシング

- 実行時接続ロード・バランシングの概要

- 実行時接続ロード・バランシングの有効化

23 パフォーマンス拡張機能

- バッチ更新

- バッチ更新モデルの概要

- Oracleバッチ更新

- Oracleバッチ更新の特性と制限事項

- 接続バッチ値の設定

- 文バッチ値の設定

- バッチ値のチェック

- バッチ値のオーバーライド

- Oracleバッチ処理での変更のコミット

- Oracleバッチ処理による更新件数

- Oracleバッチ更新におけるエラー・レポート

- 標準バッチ更新

- 標準バッチ処理のOracle実装の制限事項

- バッチに対する操作の追加

- バッチの処理

- 標準バッチ処理のOracle実装による変更のコミット

- バッチのクリア

- 標準バッチ処理のOracle実装の更新件数

- 標準バッチ処理のOracle実装におけるエラー処理

- バッチ処理される文とバッチ処理されない文の混在

- 早期バッチ・フラッシュ

- その他のOracleパフォーマンス拡張機能

- LOBデータのプリフェッチ

- Oracle行プリフェッチの制限事項

- 列型の定義

- DatabaseMetaData TABLE_REMARKSのレポート

24 OCI接続プーリング

- OCIドライバ接続プーリング: 背景

- OCIドライバ接続プーリングと共有サーバーの比較

- OCI接続プールの定義

- OCI接続プールへの接続

- OCI接続プーリングのサンプル・コード

- 文の処理とキャッシュ

- JNDIおよびOCI接続プール

25 Oracleアドバンスト・キューイング(AQ)

- Oracleアドバンスト・キューイングの機能とフレームワーク

- データベースの変更

- AQ非同期イベント通知

- メッセージの作成

- 例: メッセージの作成およびペイロードの設定

- メッセージのエンキュー

- メッセージのデキュー

- 例: エンキューとデキュー

26 データベース変更通知

- 登録エントリの作成

- 登録エントリへの問合せの関連付け

- データベース変更イベントの通知

- 登録の削除

第VI部 高可用性

27 高速接続フェイルオーバー

- 高速接続フェイルオーバーの概要

- 高速接続フェイルオーバーの使用

- 高速接続フェイルオーバーの前提条件

- 高速接続フェイルオーバー用のONSの構成

- リモートONSサブスクリプション

- 高速接続フェイルオーバーを使用可能にする

- 高速接続フェイルオーバーのステータスの問合せ

- 高速接続フェイルオーバーについて

- アプリケーションによる認識

- 実行される処理

- 高速接続フェイルオーバーとTAFの比較

28 透過的アプリケーション・フェイルオーバー

- 透過的アプリケーション・フェイルオーバーの概要

- フェイルオーバー・タイプ・イベント

- TAFコールバック

- Java TAFコールバック・インタフェース

第VII部 トランザクション管理

29 分散トランザクション

- 分散トランザクションの概要

- 分散トランザクションのコンポーネントおよびシナリオ

- 分散トランザクションの概念

- ローカル・トランザクションとグローバル・トランザクションの切替え

- Oracle XAパッケージ

- XAコンポーネント

- XADatasourceインタフェースとOracle実装

- XAConnectionインタフェースとOracle実装

- XAResourceインタフェースとOracle実装

- OracleXAResourceメソッドの機能と入力パラメータ

- XidインタフェースとOracle実装

- エラー処理と最適化

- XAExceptionクラスとメソッド

- OracleエラーとXAエラーのマッピング

- XAエラー処理

- Oracle XA最適化

- 分散トランザクションの実装

- Oracle XAのインポートの概要

- OracleのXAコード・サンプル

- Oracle JDBCドライバのネイティブXA

- OCIネイティブXA

- ThinネイティブXA

第VIII部 管理性

30 データベース管理

31 JDBCの診断機能

- ロギング

- JDBCロギングの有効化と使用

- CLASSPATHの構成

- ロギングの有効化

- ロギングの構成

- ログ出力の使用

- 例

- パフォーマンス、スケーラビリティおよびセキュリティに関する問題点

- 診断能力管理

32 JDBC DMSメトリック

- JDBC DMSメトリックの概要

- 生成されるメトリックの種類の決定

- SQLTextメトリックの生成

- JMXを使用したDMSメトリックへのアクセス

第IX部 付録

AJDBCリファレンス情報

- 有効なSQL-JDBCデータ型マッピング

- サポートされているSQLおよびPL/SQLデータ型

- 埋込みJDBCエスケープ構文

- 時刻および日付リテラル

- 日付リテラル

- 時刻リテラル

- タイムスタンプ・リテラル

- スカラー関数

- LIKEエスケープ文字

- 外部結合

- ファンクション・コール構文

- JDBCエスケープ構文からOracle SQL構文変換例

- Oracle JDBCの注意および制限事項

- CursorName

- JDBC外部結合エスケープ

- PL/SQL TABLE、BOOLEANおよびRECORD型

- IEEE 754浮動小数点との互換性

- DatabaseMetaDataコールへのCatalog引数

- SQLWarningクラス

- DDL文の実行

- 名前付きパラメータのバインド

B Oracle RAC高速アプリケーション通知

- Oracle RAC高速アプリケーション通知の概要

- Oracle RAC高速アプリケーション通知のインストールおよび構成

- ONSの構成

- ONS構成ファイルの概要

- クライアント側ONSの構成

- Oracle RAC高速アプリケーション通知の使用

- 接続キャッシュの実装

C コーディングのヒント

- JDBCとマルチスレッド

- パフォーマンスの最適化

- 自動コミット・モードの無効化

- 標準フェッチ・サイズとOracle行プリフェッチ

- 標準バッチ更新とOracleバッチ更新

- 文キャッシュ

- 組込みSQL型とJava型間のマッピング

- トランザクション分離レベルとアクセス・モード

D JDBCエラー・メッセージ

- JDBCエラー・メッセージの一般構造

- 一般JDBCメッセージ

- ORA番号でソートしたJDBCメッセージ

- 五十音順にソートしたJDBCメッセージ

- ネイティブXAメッセージ

- ORA番号でソートしたネイティブXAメッセージ

- 五十音順にソートしたネイティブXAメッセージ

- TTCメッセージ

- ORA番号でソートしたTTCメッセージ

- 五十音順にソートしたTTCメッセージ

E トラブルシューティング

- 一般的な問題

- OUTまたはIN/OUT変数として定義されたCHAR列に対するメモリー消費

- メモリー・リークおよびカーソルの不足

- PL/SQLストアド・プロシージャのブール型パラメータ

- 1プロセスで可能なOCI接続のオープン数について

- Statement.cancelの使用

- ファイアウォールとJDBCの使用方法

- 多数回にわたるサーバーからの突然の切断

- 基本的なデバッグ処理

- ネットワーク・イベントをトラップするためのOracle Netトレース

- クライアント側でのトレース

- サーバー側のトレース

- サード・パーティのデバッグ・ツール

索引

例一覧

- SQLXMLデータへのアクセス

- 4-1 SYS.ANYTYPE型へのアクセス

- 4-2 一時オブジェクト型のPL/SQLによる作成とJDBCによる取出し

- 4-3 ANYTYPEをINパラメータとして受け取るPL/SQLストアド・プロシージャのコール

- 4-4 ANYDATAのインスタンスに対するデータベースからのアクセス

- 4-5 データベース表へのANYDATAとしてのオブジェクトの挿入

- 4-6 データベース表からのANYDATA列の選択

- 8-1 リモート接続でのSYSログインの使用

- 9-1 SSL認証を使用したデータベースへの接続

- 9-2 データソースを使用したデータベースへの接続

- 9-3 データ暗号化および整合性パラメータの設定

- 9-4 Kerberos認証を使用したデータベースへの接続

- 9-5 RADIUSL認証を使用したデータベースへの接続

- 20-1 暗黙的文キャッシュの使用

- 21-1 暗黙的接続キャッシュの使用

- 21-2 接続キャッシュの例

- 21-3 接続属性の使用

- 21-4 接続プロパティの使用

- 21-5 Connection Cache Managerの例

- 23-1 Oracleバッチ更新

- 23-2 標準バッチ更新

- 23-3 早期バッチ・フラッシュ

- 23-4 列型の定義

- 23-5 TABLE_REMARKSレポート

- 25-1 メッセージの作成およびペイロードの設定

- 25-2 単一メッセージのエンキュー

- 25-3 単一メッセージのデキュー

- 26-1 データベース変更通知

- 27-1 高速接続フェイルオーバーの有効化

- 30-1 データベースの起動と停止

- B-1 ons.configサンプル・ファイルの例

- B-2 Oracle RAC FAN APIを使用するサンプル・コードの例

図一覧

- 1-1 Oracle JDBCドライバとOracle Databaseのアーキテクチャ

- 5-1 アプレット、Connection Managerおよびデータベースの関係

- 22-1 実行時接続ロード・バランシング

表一覧

- 1-1 JDBC OCIドライバとJDBC Thinドライバの機能の相違点

- 1-2 機能リスト

- 2-1 JDBCドライバ用のimport文

- 3-1 JDBC 3.0機能の主な領域

- 3-2 等価のBLOBメソッド

- 3-3 等価のCLOBメソッド

- 4-1 oracle.jdbcパッケージの主なインタフェースおよびクラス

- 4-2 PL/SQL型と対応するJDBC型

- 4-3 setPlsqlIndexTableメソッドの引数

- 4-4 registerIndexTableOutParameterメソッドの引数

- 4-5 getPlsqlIndexTableメソッドの引数

- 4-6 getOraclePlsqlIndexTableメソッドの引数

- 4-7 getPlsqlIndexTableメソッドの引数

- 6-1 OCI Instant Client共有ライブラリ

- 6-2 Instant ClientおよびInstant Client Light(English)のデータ共有ライブラリ

- 8-1 標準データソース・プロパティ

- 8-2 Oracle拡張データソース・プロパティ

- 8-3 サポートされるデータベース指定子

- 9-1 暗号化または整合性のためのクライアント/サーバー間ネゴシエーション表

- 9-2 暗号化と整合性のためのOCIドライバ・クライアント・パラメータ

- 9-3 暗号化と整合性のためのThinドライバ・クライアント・パラメータ

- 11-1 SQL型とJava型間のデフォルト・マッピング

- 11-2 getObjectおよびgetOracleObjectの戻り型

- 12-1 LONGおよびLONG RAWデータの変換

- 13-1 JPublisherのSQL型カテゴリ、サポートされる設定およびデフォルト

- 17-1 Oracle JDBCでの内部変更および外部変更の可視性

- 18-1 JDBCのRowSetとCachedRowSetの比較

- 20-1 文キャッシュで使用されるメソッドの比較

- 20-2 文の割当ておよび暗黙的文キャッシュで使用されるメソッド

- 20-3 明示的にキャッシュされた文を取り出す場合に使用するメソッド

- 23-1 有効な列型

- 26-1 データベース変更通知登録オプション

- 29-1 接続モードの推移

- 29-2 OracleとXAのエラー・マッピング

- 30-1 サポートされているデータベース起動オプション

- 30-2 サポートされているデータベース停止オプション

- A-1 有効なSQLデータ型-Javaクラス・マッピング

- A-2 SQLデータ型に対するサポート

- A-3 ANSI-92 SQLデータ型に対するサポート

- A-4 SQLユーザー定義型に対するサポート

- A-5 PL/SQLデータ型に対するサポート

- B-1 必須のONS構成パラメータ

- B-2 オプションのONS構成パラメータ

- B-3 onsctlコマンド

- D-1 ORA番号でソートしたJDBCメッセージ

- D-2 五十音順にソートしたJDBCメッセージ

- D-3 ORA番号でソートしたネイティブXAメッセージ

- D-4 五十音順にソートしたネイティブXAメッセージ

- D-5 ORA番号でソートしたTTCメッセージ

- D-6 五十音順にソートしたTTCメッセージ

Oracle® Database

JDBC開発者ガイド

11gリリース2(11.2)

B56281-02(原本部品番号:E16548-03)

2011年9月

このマニュアルでは、Oracle JDBCドライバを使用して強力なJavaデータベース・アプリケーションを開発する方法を説明します。

Oracle Database JDBC開発者ガイド11gリリース2(11.2)

B56281-02

Copyright © 1999, 2011, Oracle and/or its affiliates.All rights reserved.

原本著者:  Tulika Das, Venkatasubramaniam Iyer, Elizabeth Hanes Perry, Brian Wright, Thomas Pfaeffle

原本協力著者:  Brian Martin

原本協力者:  Kuassi Mensah, Douglas Surber, Paul Lo, Ed Shirk, Tong Zhou, Jean de Lavarene, Rajkumar Irudayaraj, Ashok Shivarudraiah, Angela Barone, Rosie Chen, Sunil Kunisetty, Joyce Yang, Mehul Bastawala, Luxi Chidambaran, Srinath Krishnaswamy, Longxing Deng, Magdi Morsi, Ron Peterson, Ekkehard Rohwedder, Catherine Wong, Scott Urman, Jerry Schwarz, Steve Ding, Soulaiman Htite, Anthony Lai, Prabha Krishna, Ellen Siegal, Susan Kraft, Sheryl Maring

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントが、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供される場合は、次のNoticeが適用されます。

U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software License (December 2007).Oracle America, Inc., 500 Oracle Parkway, Redwood City, CA 94065.

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、このソフトウェアまたはハードウェアを安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle およびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXはThe Open Groupの登録商標です。

このソフトウェアまたはハードウェアおよびドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

はじめに

この章では、『Oracle Database JDBC開発者ガイド』の概要、対象読者、構成および表記規則について説明します。関連するOracleドキュメントのリストも提供します。

この章の構成は、次のとおりです。

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

対象読者

『Oracle Database JDBC開発者ガイド』はJava Database Connectivity (JDBC)に基づくアプリケーションやアプレットの開発者を対象としています。このマニュアルは、JDBCプログラミングに関心のあるすべての読者を対象にしていますが、次の事項に関するいくらかの予備知識があることを前提にしています。

- Java

- Oracle PL/SQL

- Oracleデータベース

ドキュメントのアクセシビリティについて

オラクル社のアクセシビリティへの取組みの詳細は、Oracle Accessibility ProgramのWebサイトhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=docaccを参照してください。

Oracleサポートへのアクセス

Oracleカスタマは、My Oracle Supportから電子サポートにアクセスできます。詳細は、http://www.oracle.com/pls/topic/lookup?ctx=acc&id=infoまたはhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs (聴覚障害者向け)を参照してください。

外部Webサイトのドキュメントのアクセシビリティについて

このドキュメントにはオラクル社およびその関連会社が所有または管理しないWebサイトへのリンクが含まれている場合があります。オラクル社およびその関連会社は、それらのWebサイトのアクセシビリティに関しての評価や言及は行っておりません。

聴覚に障害があるお客様のOracleサポート・サービスへのアクセス

Oracleサポート・サービスに連絡するために、電気通信リレー・サービス(TRS)を使用して、1.800.223.1711でOracle Supportに電話してください。Oracleサポート・サービスのエンジニアは、技術的な問題を処理し、Oracleサービス要求処理に応じてカスタマ・サポートを提供します。TRSの詳細はhttp://www.fcc.gov/cgb/consumerfacts/trs.html、電話番号の一覧についてはhttp://www.fcc.gov/cgb/dro/trsphonebk.htmlを参照してください。

関連ドキュメント

次のマニュアルは、Oracle Java Platformグループからも利用できます。

- 『Oracle Database Java開発者ガイド』
このマニュアルでは、Javaの基本概念を導入し、サーバー側の構成と機能に関する一般的な情報を提供します。特定の製品(たとえばJDBC)よりむしろOracle Javaプラットフォーム全体に関係している情報はこのマニュアルに記載されています。このマニュアルは、以前は独立したマニュアルで説明されていた、Javaストアド・プロシージャについても説明しています。

- 『Oracle Database JPublisherユーザーズ・ガイド』
このマニュアルでは、Oracle JPublisherユーティリティを使用して、オブジェクト型やその他のユーザー定義の型をJavaクラスに変換する方法を説明しています。オブジェクト型、VARRAY型、ネスト表型またはオブジェクト参照型を使用するJDBCアプリケーションを開発している場合、JPublisherでそれらにマップするカスタムJavaクラスを生成することができます。

Oracle Application Serverリリース向けの次のOC4Jドキュメントは、Oracle Java Platformグループからも利用できます。

- 『Oracle Application Server Containers for J2EEユーザーズ・ガイド』
このマニュアルには、サーブレット、JSPページおよびEJBの入門、一般的な構成とデプロイメントの手順など、OC4Jの概要と一般的な情報があります。

- 『Oracle Containers for J2EE JavaServer Pages開発者ガイド』
このマニュアルでは、ページをOC4Jで実行するJSP開発者向けの情報を提供します。JSP標準の一般的な概要とプログラミング上の考慮事項、付加価値をもたらすOracleの機能の説明、OC4J環境の入門手順などが含まれます。

- 『Oracle Containers for J2EE JSPタグ・ライブラリおよびユーティリティ・リファレンス』
このマニュアルでは、OC4Jで提供されるタグ・ライブラリ、JavaBeansおよびその他のJavaユーティリティの概念に関する情報や、構文および使用方法に関する詳細情報を提供します。

- Oracle Application Server Containers for J2EEサーブレット開発者ガイド
このマニュアルでは、OC4Jでのサーブレットとサーブレット・コンテナの使用に関する、サーブレット開発者向けの情報を提供します。また、関連のOC4J構成ファイルについても説明しています。

- 『Oracle Containers for J2EEサービス・ガイド』
このマニュアルでは、OC4Jで提供される基本的なJavaサービス(JTA、JNDI、Oracle Application Server Javaオブジェクト・キャッシュなど)に関する情報を提供します。

- 『Oracle Containers for J2EE Enterprise JavaBeans開発者ガイド』
このマニュアルでは、OC4JでのEJB実装とEJBコンテナに関する情報を提供します。

次のドキュメントは、Oracle Server Technologiesグループから利用できます。

- Oracle Databaseアドバンスト・アプリケーション開発者ガイド

- 『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』

- Oracle Database PL/SQL言語リファレンス

- Oracle Database SQL言語リファレンス

- 『Oracle Database Net Services管理者ガイド』

- 『Oracle Database Advanced Security管理者ガイド』

- 『Oracle Databaseリファレンス』

- 『Oracle Databaseエラー・メッセージ』

Oracle Application Serverグループの次のドキュメントも参考になります。

- 『Oracle Application Server管理者ガイド』

- 『Oracle Fusion Middleware Oracle HTTP Server管理者ガイド』

- 『Oracle Fusion Middleware Performance Guide』

- Oracle Fusion Middlewareアプリケーション・グローバリゼーション・ガイド

- 『Oracle Fusion Middleware Oracle Web Cache管理者ガイド』

- 『Oracle Fusion Middlewareアップグレード・プランニング・ガイド』

次のものは、JDeveloperグループから利用できます。

- Oracle JDeveloperのオンライン・ヘルプ

- Technology Network上のJDeveloperマニュアル
http://www.oracle.com/technetwork/developer-tools/jdev/overview/index.html

印刷されたマニュアルは次のURLのOracle Storeで入手できます。

http://oraclestore.oracle.com/

リリース・ノート、インストール関連ドキュメント、ホワイト・ペーパーまたはその他の関連ドキュメントは、OTN (Oracle Technology Network)から、無償でダウンロードできます。OTN-Jを使用するには、オンラインでの登録が必要です。登録は、次のWebサイトから無償で行えます。

http://www.oracle.com/technetwork/community/join/overview/index.html

すでにOTNのユーザー名およびパスワードを取得している場合は、次のURLでOTN Webサイトのドキュメントのセクションに直接接続できます。

http://www.oracle.com/technetwork/documentation/index.html

次のリソースは、Sun Microsystemsから利用できます。

- 最新の仕様などがある、JDBCに関するWebサイト。
http://www.oracle.com/technetwork/java/javase/jdbc/index.html

表記規則

このセクションでは、このマニュアルの本文およびコード例で使用される表記規則について説明します。この項の内容は次のとおりです。

- 本文の表記規則

- コード例の表記規則

- Microsoft Windowsオペレーティング・システム環境での表記規則

本文の表記規則

本文では、特定の項目が一目でわかるように、次の表記規則を使用します。その規則と使用例を示します。

規則

意味

例

太字

太字は、本文中で定義されている用語または用語集に記載されている用語(あるいはその両方)を示します。

この句を指定すると、索引構成表が作成されます。

イタリック

イタリックは、ドキュメントのタイトルまたは強調を示します。

Oracle Database
リカバリ・カタログおよびターゲット・データベースが同じディスクに存在しないことを確認します。

固定幅フォントの大文字

固定幅フォントの大文字は、システム指定の要素を示します。このような要素には、パラメータ、権限、データ型、Recovery Managerキーワード、SQLキーワード、SQL*Plusまたはユーティリティ・コマンド、パッケージおよびメソッドがあります。また、システム指定の列名、データベース・オブジェクト、データベース構造、ユーザー名およびロールも含まれます。

NUMBER列に対してのみ、この句を指定できます。
BACKUPコマンドを使用して、データベースのバックアップを作成できます。

USER_TABLESデータ・ディクショナリ・ビュー内のTABLE_NAME列を問い合せます。

DBMS_STATS.GENERATE_STATSプロシージャを使用します。

固定幅フォントの小文字

固定幅フォントの小文字は、実行可能ファイル、ファイル名、ディレクトリ名およびユーザーが指定する要素のサンプルを示します。このような要素には、コンピュータ名およびデータベース名、ネット・サービス名および接続識別子があります。また、ユーザーが指定するデータベース・オブジェクトとデータベース構造、列名、パッケージとクラス、ユーザー名とロール、プログラム・ユニットおよびパラメータ値も含まれます。
注意: プログラム要素には、大文字と小文字を組み合せて使用するものもあります。これらの要素は、記載されているとおりに入力してください。

sqlplusと入力して、SQL*Plusをオープンします。
パスワードは、orapwdファイルで指定します。

/disk1/oracle/dbsディレクトリ内のデータ・ファイルおよび制御ファイルのバックアップを作成します。

hr.departments表には、department_id、department_nameおよびlocation_id列があります。

QUERY_REWRITE_ENABLED初期化パラメータをtrueに設定します。

oeユーザーとして接続します。

JRepUtilクラスが次のメソッドを実装します。

固定幅フォントの小文字のイタリック

固定幅フォントの小文字のイタリックは、プレースホルダまたは変数を示します。

parallel_clauseを指定できます。
old_release.SQLを実行します。ここで、old_releaseとは、アップグレード前にインストールしたリリースを示します。

コード例の表記規則

コード例では、Javaの文、SQL文およびコマンドライン文を示しています。例は次のように固定幅フォントで表示され、通常のテキストと区別されます。

SELECT username FROM dba_users WHERE username = 'MIGRATE';

次の表に、コード例で使用される表記規則とその使用例を示します。

規則

意味

例

[ ]

大カッコは、カッコ内の項目を任意に選択することを表します。大カッコは、入力しないでください。

DECIMAL (digits [ , precision ])

{ }

中カッコは、カッコ内の項目のうち、1つが必須であることを表します。中カッコは、入力しないでください。

{ENABLE | DISABLE}

|

縦線は、大カッコまたは中カッコ内の複数の選択項目の区切りに使用します。項目のうちの1つを入力します。縦線は、入力しないでください。

{ENABLE | DISABLE}
[COMPRESS | NOCOMPRESS]

...

水平の省略記号は、次のいずれかを示します。

- 例に直接関連しないコードの一部が省略されている。

- コードの一部を繰り返すことができる。

CREATE TABLE ... AS subquery;

SELECT col1, col2, ... , coln FROM employees;

.
.
.

垂直の省略記号は、例に直接関連しない複数の行が省略されていることを示します。

SQL> SELECT NAME FROM V$DATAFILE;
NAME
------------------------------------
/fsl/dbs/tbs_01.dbf
/fs1/dbs/tbs_02.dbf
.
.
.
/fsl/dbs/tbs_09.dbf
9 rows selected.

その他の記号

大カッコ、中カッコ、縦線および省略記号以外の記号は、記載されているとおりに入力する必要があります。

acctbal NUMBER(11,2);
acct    CONSTANT NUMBER(4) := 3;

Italics

イタリック体は、特定の値を指定する必要があるプレースホルダや変数を示します。

CONNECT SYSTEM/system_password
DB_NAME = database_name

UPPERCASE

大文字は、システム指定の要素を示します。これらの要素は、ユーザー定義の要素と区別するために大文字で示されます。大カッコ内にないかぎり、表示されているとおりの順序および綴りで入力します。ただし、大/小文字が区別されないため、小文字でも入力できます。

SELECT last_name, employee_id FROM employees;
SELECT * FROM USER_TABLES;
DROP TABLE hr.employees;

lowercase

小文字は、ユーザー指定のプログラム要素を示します。たとえば、表名、列名またはファイル名などです。
注意: プログラム要素には、大文字と小文字を組み合せて使用するものもあります。これらの要素は、記載されているとおりに入力してください。

SELECT last_name, employee_id FROM employees;
sqlplus hr/hr
CREATE USER mjones IDENTIFIED BY ty3MU9;

Microsoft Windowsオペレーティング・システム環境での表記規則

次の表に、Microsoft Windowsオペレーティング・システム環境での表記規則とその使用例を示します。

規則

意味

例

「スタート」>を選択

プログラムを起動する方法を示します。

Database Configuration Assistantを起動するには、「スタート」→「すべてのプログラム」→「Oracle - HOME_NAME」→「Configuration and Migration Tools」→「Database Configuration Assistant」の順に選択します。

ファイル名およびディレクトリ名

ファイル名およびディレクトリ名は大/小文字が区別されません。特殊文字の左山カッコ(<)、右山カッコ(>)、コロン(:)、二重引用符(")、スラッシュ(/)、縦線(|)およびハイフン(-)は使用できません。特殊文字の円記号(￥)は、引用符で囲まれている場合でも、要素のセパレータとして処理されます。Windowsでは、ファイル名が￥￥で始まる場合、汎用命名規則が使用されていると解釈されます。

c:\winnt"\"system32 is the same as C:\WINNT\SYSTEM32

Windowsコマンド・プロンプト>

現在のハード・ディスク・ドライブのWindowsコマンド・プロンプトを表します。コマンド・プロンプトのエスケープ文字はカレット(^)です。プロンプトは作業中のサブディレクトリを表します。このマニュアルでは、コマンド・プロンプトと呼びます。

C:\oracle\oradata>

特殊文字

Windowsコマンド・プロンプトで二重引用符(")のエスケープ文字として円記号(￥)が必要な場合があります。丸カッコおよび一重引用符(')にはエスケープ文字は必要ありません。エスケープ文字および特殊文字の詳細は、Windowsオペレーティング・システムのドキュメントを参照してください。

C:\>exp scott/tiger TABLES=emp QUERY=\"WHERE job='SALESMAN' and sal<1600\"
C:\>imp SYSTEM/password FROMUSER=scott TABLES=(emp, dept)

HOME_NAME

Oracleホームの名前を表します。ホーム名には、英数字で16文字まで使用できます。ホーム名に使用可能な特殊文字は、アンダースコアのみです。

C:\> net start OracleHOME_NAMETNSListener

ORACLE_HOMEおよびORACLE_BASE

Oracle8iより前のリリースでは、Oracleコンポーネントをインストールすると、すべてのサブディレクトリが最上位のORACLE_HOMEの直下に置かれました。ディレクトリの名前は、デフォルトでは次のいずれかです。

- C:\orant(Windows NTの場合)

- C:\orawin98(Windows 98の場合)

このリリースは、Optimal Flexible Architecture (OFA)のガイドラインに準拠しています。ORACLE_HOMEディレクトリ下に配置されないサブディレクトリもあります。最上位のディレクトリはORACLE_BASEと呼ばれ、デフォルトではC:¥oracle¥です。他のOracleソフトウェアがインストールされていないコンピュータに最新リリースのOracleをインストールした場合、Oracleホーム・ディレクトリはデフォルトでC:¥oracle¥orannに設定されます。nnは最新リリースの番号です。Oracleホーム・ディレクトリは、ORACLE_BASEの直下に配置されます。

このマニュアルに示すディレクトリ・パスの例は、すべてOFAの表記規則に準拠しています。

OFAの準拠の詳細、および非OFA準拠ディレクトリ下でのOracle製品のインストールの詳細は、『Oracle Databaseプラットフォーム・ガイド for Microsoft Windows』を参照してください。

ORACLE_BASE\ORACLE_HOME\rdbms\adminディレクトリに移動します。

新機能

この章では、Oracle Database 11gリリース2(11.2)JDBCドライバの新機能について説明します。

リリース2(11.2)の新機能

今回のリリースで、Oracle JDBCドライバでは次の新機能をサポートしています。

- SQLXMLのサポート

- タイムスタンプとタイム・ゾーンの改善

- LOBプリフェッチのサポート

- Oracle SecureFilesのゼロコピーI/O

- 接続のためのセッション・エディションの設定

- インターネット・プロトコル・バージョン(IPv6)のサポート

- PreparedStatement.getMetaData()メソッド

- Oracle RAC高速アプリケーション通知

- ユニバーサル接続プール

- OCIクライアント結果キャッシュ拡張

SQLXMLのサポート

Oracle JDBCドライバのこのリリースは、SQL/XMLデータベース・データ型をサポートするためのマッピング・インタフェースを提供します。SQL/XMLデータベース・データ型の詳細は、「SQLXML型」を参照してください。

タイムスタンプとタイム・ゾーンの改善

タイム・ゾーンのバージョン非互換性関連の問題に対応するために、新たに設計されたタイム・ゾーン・キャッシュが備わっています。詳細は、「oracle.sql.TIMESTAMP、oracle.sql.TIMESTAMPTZおよびoracle.sql.TIMESTAMPLTZクラスの概要」を参照してください。

LOBプリフェッチのサポート

データベースへのラウンドトリップ数を減らすことにより、LOB操作のパフォーマンスが向上しました。詳細は、「LOBデータのプリフェッチ」を参照してください。

Oracle SecureFilesのゼロコピーI/O

ゼロコピーI/Oフレームワークの使用により、LOB操作が速くなりました。詳細は、「Oracle SecureFiles用のゼロコピーI/O」を参照してください。

接続のためのセッション・エディションの設定

データベースに接続するときに、ユーザー名、パスワード、システム権限、接続識別子に加えて、セッション・エディションをコードに指定できるようになりました。詳細は、『Oracle Database JDBC Java API Reference』を参照してください。

関連項目:
セッション・エディションの詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。

インターネット・プロトコル・バージョン(IPv6)のサポート

インターネット・プロトコル・バージョン6(IPv6)のアドレスをサポートします。詳細は、「インターネット・プロトコル・バージョン6のサポート」を参照してください。

注意:
IPv6のサポートに必要な新しいシステム・クラスはすべて、データベースの初期化中に有効になります。したがって、アプリケーションにIPv6アドレスがない場合は、IPv6機能を使用するために自分のコードを変更する必要はありません。ただし、アプリケーションにIPv6アドレスのみか、IPv6とIPv4アドレスの両方のいずれかがある場合、コマンドラインでjava.net.preferIPv6Addressesシステム・プロパティを設定する必要があります。これにより、Oracle JVMは適切なライブラリをロードできるようになります。これらのライブラリは一度ロードすると、Javaプロセスを再起動しないかぎりリロードできません。

PreparedStatement.getMetaData()メソッド

Oracle Database 11gリリース2(11.2)では、JDBCドライバは、PreparedStatementを実行しない、SELECT文のメタデータの取得をサポートしています。この機能は、以前のデータベース・リリースでも動作します。詳細は、「インタフェースoracle.jdbc.OraclePreparedStatement」を参照してください。

Oracle RAC高速アプリケーション通知

Oracle Database 11gリリース2(11.2)では、Oracle RAC高速アプリケーション通知(FAN)イベントへのアクセス用に簡略化されたAPIが導入されました。この機能により、Oracle Databaseの高可用性機能を最大限に利用する、よりレスポンスのよいアプリケーションを開発できます。詳細は、「Oracle RAC高速アプリケーション通知」を参照してください。

ユニバーサル接続プール

Oracle Database 11gリリース2(11.2)には、Oracle Universal Connection Pool(UCP)for JDBCが含まれています。Oracle Universal Connection Pool(UCP)は、データベース接続を管理するためのフル機能搭載の接続プールです。データベース集中型のJavaアプリケーションは、接続プールを使用してパフォーマンスを向上させ、システム・リソースを効率的に利用します。

注意:
Oracle Universal Connection Pool(UCP)for JDBCは、Oracle Database 11.1.0.7リリースで導入されました。

関連項目:
『Oracle Universal Connection Pool for JDBC開発者ガイド』

OCIクライアント結果キャッシュ拡張

Oracle Call Interface(OCI)クライアント結果キャッシュ機能は、Oracle Database 11gリリース2(11.2)で拡張されています。クライアント結果キャッシュは、表注釈、およびビューによる問合せ時のキャッシュをサポートします。また、クライアント・キャッシュでデータベースにあるプーリングを無効にする制限が削除されています。詳細は、「クライアント結果キャッシュ」を参照してください。

第I部

概要

第I部では、Java Database Connectivity(JDBC)の概念を紹介し、JDBCのOracle実装の概要を説明します。JDBCドライバに関して、Oracleクライアントのインストールと構成の基本情報を提供します。また、JDBCアプリケーションの作成および実行の基本手順についても説明します。

第I部の構成は次のとおりです。

- 第1章「JDBCの概要」

- 第2章「スタート・ガイド」

関連項目:

- Oracle Database JDBC Java APIリファレンス

1 JDBCの概要

Java Database Connectivity(JDBC)は、Javaからリレーショナル・データベースに接続するためのインタフェースを提供するJava標準です。JDBC標準はSun社によって定義され、標準のjava.sqlインタフェースを介して実装されます。このため、各プロバイダは独自のJDBCドライバで標準を実装および拡張できます。JDBCは、X/Open SQLコール・レベル・インタフェース(CLI)に基づいています。JDBC 4.0では、SQL 2003標準を使用してコンパイルします。

この章では、JDBCのOracle実装の概要を説明します。内容は次のとおりです。

- Oracle JDBCドライバの概要

- 環境およびサポート

- 機能リスト

Oracle JDBCドライバの概要

Oracleドライバは、標準JDBC Application Program Interface(API)をサポートする他、Oracle固有のデータ型をサポートし、パフォーマンスを向上させる拡張機能を備えています。

次のJDBCドライバがあります。

- Thinドライバ
クライアント側で使用されるPure Javaドライバで、Oracleクライアントのインストールは必要ありません。アプレットとアプリケーションの両方で使用できます。

- Oracle Call Interface(OCI)ドライバ
クライアント側で使用されるドライバで、Oracleクライアントのインストールが必要です。アプリケーションでのみ使用できます。

- サーバー側Thinドライバ
機能的にはクライアント側Thinドライバと同じです。ただし、データベース・サーバーで実行され、同じサーバーまたは任意の層のリモート・サーバーで別セッションにアクセスする必要があるコード用です。

- サーバー側内部ドライバ
データベース・サーバーで実行され、同じセッションにアクセスするコード用です。つまり、このコードは、単一のOracleセッションから実行され、データにアクセスします。

図1-1は、Oracle JDBCドライバとOracle Databaseのアーキテクチャを示しています。

図1-1 Oracle JDBCドライバとOracle Databaseのアーキテクチャ

「図1-1 Oracle JDBCドライバとOracle Databaseのアーキテクチャ」の説明

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

- Oracle JDBCドライバの共通機能

- 適切なドライバの選択

- JDBC OCIドライバとJDBC Thinドライバの機能の相違点

Oracle JDBCドライバの共通機能

サーバー側とクライアント側のOracle JDBCドライバの基本機能は同じです。

JDBC ThinドライバとOCIドライバは、Java Development Kit (JDK) 1.5および1.6をサポートします。サーバー側の内部ドライバは、JDK 1.5のみサポートします。JDBCドライバはすべて、次の標準と機能をサポートします。

- 共通の構文とAPI

- 共通のOracle拡張機能

- マルチスレッド・アプリケーションの完全なサポート

Oracle JDBCドライバは、標準のjava.sqlインタフェースを実装します。標準の機能に加えて、oracle.jdbcパッケージを使用することにより、Oracle固有の機能へのアクセスが可能になります。

JDBC Thinドライバ

JDBC Thinドライバは、Pure JavaのType IVドライバで、アプリケーションおよびアプレットで使用できます。プラットフォームに依存せず、クライアント側に追加のOracleソフトウェアは必要ありません。JDBC Thinドライバは、Oracle DatabaseにアクセスするためにSQL*Netを使用してサーバーと通信します。

JDBC Thinドライバを使用すると、Javaソケット上にSQL*Netを実装することで、データベースに直接接続できます。このドライバでは、TCP/IPプロトコルがサポートされており、データベース・サーバーのTCP/IPソケットにTNSリスナーが必要です。

関連項目:
第5章「JDBC Thin固有の機能」

JDBC OCIドライバ

JDBC OCIドライバは、Javaアプリケーション用のType IIドライバです。このドライバは、Oracleクライアントのインストールが必要であるため、Oracleプラットフォーム固有です。IPC(プロセス間通信)、名前付きパイプ、TCP/IPおよびInternetwork Packet Exchange/Sequenced Packet Exchange(IPX/SPX)を含む、インストールされたすべてのOracle Netアダプタをサポートします。

JDBC OCIドライバはJavaとCを組み合せて記述されており、Cエントリ・ポイントをコールするネイティブ・メソッドを使用してJDBCの起動をOCIへのコールに変換します。これらのコールは、SQL*Netを使用してデータベースとの通信を行います。

JDBC OCIドライバは、インストールされたクライアント・コンピュータにあるOCIライブラリ、Cエントリ・ポイント、Oracle Net、コア・ライブラリおよびその他の必要なファイルを使用します。

OCIは、第3世代言語のネイティブ・プロシージャやファンクション・コールを使用して、Oracle Databaseにアクセスし、SQL文処理のすべての段階を制御するアプリケーションを作成できるようにするAPIです。

関連項目:
第6章「JDBC OCIドライバ固有の機能」

JDBCサーバー側Thinドライバ

JDBCサーバー側Thinドライバは、クライアント側で実行されるJDBC Thinドライバと同じ機能を提供します。ただし、Oracle Databaseの内部で実行され、リモート・データベース、または同じデータベースの別セッションにアクセスします。

このドライバは、次の場合に役立ちます。

- 中間層として機能を果すOracle Databaseインスタンスからリモートのデータベース・サーバーにアクセスする場合

- Javaストアド・プロシージャなどのOracle Databaseセッションの内部から別のOracle Databaseセッションにアクセスする場合

JDBC Thinドライバをクライアント・アプリケーションから使用する場合とサーバーの内部から使用する場合で、コード上の違いはありません。

関連項目:
第5章「JDBC Thin固有の機能」

JDBCサーバー側内部ドライバ

JDBCサーバー側内部ドライバは、Javaストアド・プロシージャなど、Oracle Databaseの内部で実行され、同じデータベースにアクセスする必要がある、あらゆるJavaコードをサポートします。このドライバにより、Oracle Java仮想マシン(Oracle JVM)はSQLエンジンと直接通信できます。このドライバでは、JDK 1.5のみをサポートしています。

JDBCサーバー側の内部ドライバ、Oracle JVM、データベースおよびSQLエンジンは、すべて同じアドレス空間の中で実行されます。このため、ネットワーク・ラウンドトリップの問題は関係ありません。プログラムは、関数呼出しを使用してSQLエンジンにアクセスします。

注意:
サーバー側内部ドライバでは、StatementクラスのcancelおよびsetQueryTimeoutメソッドはサポートされません。

JDBCサーバー側内部ドライバは、クライアント側ドライバとの一貫性を保ち、同一の機能と拡張機能をサポートします。

関連項目:
第7章「サーバー側内部ドライバ」

適切なドライバの選択

アプリケーションまたはアプレット用のJDBCドライバを選択するときには、次の点を考慮します。

- 一般的に、TCP/IP以外のネットワークのサポートなどのOCI固有の機能が必要でないかぎり、JDBC Thinドライバを使用します。

- 最大限の移植性とパフォーマンスを実現するには、JDBC Thinドライバを使用します。JDBC Thinドライバを使用すると、アプリケーションとアプレットのどちらからでもOracle Databaseに接続できます。

- Secure Sockets Layer(SSL)を介してLightweight Directory Access Protocol(LDAP)を使用する場合は、JDBC Thinドライバを使用します。

- Oracleクライアントの環境で使用するクライアント・アプリケーションを作成し、TCP/IP以外のネットワークのサポートなど、OCIドライバ固有の機能が必要な場合は、JDBC OCIドライバを使用します。

- アプレットを作成する場合は、JDBC Thinドライバを使用します。

- データベース・サーバー内で動作し、リモート・データベースまたは同じデータベース・インスタンス内の別のセッションにアクセスする必要があるコードの場合は、JDBCサーバー側Thinドライバを使用します。

- コードがデータベース・サーバー内で動作し、セッション内でローカルにデータにアクセスする必要がある場合は、JDBCサーバー側内部ドライバを使用して、該当するサーバーにアクセスします。

JDBC OCIドライバとJDBC Thinドライバの機能の相違点

表1-1は、Oracle Database 11gリリース1(11.1)のJDBC OCIドライバまたはJDBC Thinドライバ固有の機能の一覧です。

表1-1 JDBC OCIドライバとJDBC Thinドライバの機能の相違点

JDBC OCIドライバ

JDBC Thinドライバ

OCI接続プーリング

ネイティブXAのデフォルト・サポート

透過的アプリケーション・フェイルオーバー(TAF)

OCIクライアント結果キャッシュ

注意:

- OCIの最適化フェッチおよびクライアント側オブジェクト・キャッシュの機能は、JDBC OCIドライバの内部機能であり、JDBC Thinドライバには適用されません。

- JDBC OCIドライバ機能の一部は、OCIライブラリから継承されたもので、Thin JDBCドライバでは使用できません。

環境およびサポート

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

- サポートされるJDKおよびJDBCのバージョン

- JNI環境およびJava環境

- JDBCとIDE

サポートされるJDKおよびJDBCのバージョン

Oracle Database 11g リリース2(11.2)では、JDBCドライバはすべてJDK 1.5と互換性を持ちます。JDBC ThinドライバとOCIドライバは、JDK 1.6もサポートします。1.5より前のJDKのバージョンはいずれも、もうサポートされていません。JDK 1.5と1.6のサポートは、それぞれojdbc5.jarファイルとojdbc6.jarファイルによって提供されます。

関連項目:
「Oracle JDBCドライバのバージョン互換性」

JNI環境およびJava環境

JDBC OCIドライバは、OCI Cライブラリのコールに、標準Javaネイティブ・インタフェース(JNI)を使用しています。Sun社以外のJava仮想マシン(JVM)、特にMicrosoft社やIBM社のJVMでJDBC OCIドライバを使用できます。

JDBCとIDE

Oracle JDeveloper Suiteは、開発者に対し、インターネット用のコンポーネント・ベースのデータベース・アプリケーションを作成、デバッグおよびデプロイするための、単一の統合された製品群を提供します。Oracle JDeveloper環境には、JDBC Thinドライバおよびシステム固有のOCIドライバなど、JDBCの統合サポートが含まれています。Oracle JDeveloperのデータベース・コンポーネントは、JDBCドライバを使用してクライアントとサーバー上で稼働するアプリケーション間の接続を管理します。

機能リスト

表1-2は、各機能と、3つのOracle JDBCドライバ(サーバー側内部ドライバ、JDBC OCIおよびJDBC Thinドライバ)でその機能のサポートが開始されたバージョンのリストです。

表1-2 機能リスト

機能

サーバー側内部

JDBC OCI

JDBC Thin

JDK 1.0

7.2.2

7.2.2

JDBC 1.0.2

7.2.2

7.2.2

JDK 1.1.1

8.0.6

8.0.6

JDBC 1.22(新機能なし、マイナーな改訂のみ)

8.0.6

8.0.6

defineColumnType

8.0.6

8.0.6

行のプリフェッチ

8.0.6

8.0.6

Oracleバッチ処理

8.0.6

8.0.6

Javaネイティブ・インタフェース

8.1.6

JDK 1.2

9.0.1

8.1.6

8.1.6

JDBC 2.0 SQL3型(BLOB、CLOB、Struct、Array、REF)

8.1.5

8.1.5

8.1.5

ネイティブLOB

8.1.6

9.2.0

索引付き表

10.2.0

8.1.6

10.1.0

JDBC 2.0スクロール可能な結果セット

8.1.6

8.1.6

8.1.6

JDBC 2.0更新可能な結果セット

8.1.6

8.1.6

8.1.6

JDBC 2.0標準バッチ処理

8.1.6

8.1.6

8.1.6

JDBC 2.0接続プーリング

N/A

8.1.6

8.1.6

JDBC 2.0 XA

8.1.6

8.1.6

8.1.6

サーバー側Thinドライバ

8.1.6

N/A

N/A

JDBC 2.0 RowSet

9.0.1

9.0.1

暗黙的文キャッシュ

8.1.7

8.1.7

8.1.7

明示的文キャッシュ

8.1.7

8.1.7

8.1.7

一時LOB

9.0.1

9.0.1

9.0.1

オブジェクト型の継承

9.0.1

9.0.1

9.0.1

マルチ・レベル・コレクション

9.0.1

9.0.1

9.0.1

oracle.jdbcインタフェース

9.0.1

9.0.1

9.0.1

ネイティブXA

9.0.1

10.1.0

OCI接続プーリング

N/A

9.0.1

N/A

TAF

N/A

9.0.1

N/A

NLSサポート

9.0.1

9.0.1

9.0.1

JDK 1.3

9.2.0

9.2.0

9.2.0

JDK 1.4

10.1.0

9.2.0

9.2.0

JDBC 3.0セーブポイント

9.2.0

9.2.0

9.2.0

新規文キャッシュAPI

9.2.0

9.2.0

9.2.0

ConnectionCacheImpl接続キャッシュ

N/A

8.1.7

8.1.7

暗黙的接続キャッシュ

N/A

10.1.0

10.1.0

高速接続フェイルオーバー

10.1.0.3

10.1.0.3

接続ラップ

9.2.0

9.2.0

DMS

9.2.0

9.2.0

URLのサービス名

9.2.0

10.2.0

JDBC 3.0接続プーリング・プロパティ

N/A

10.1.0

10.1.0

JDBC 3.0更新可能なBLOB、CLOB、REF

10.1.0

10.1.0

10.1.0

JDBC 3.0複数の結果セットのオープン

10.1.0

10.1.0

10.1.0

JDBC 3.0パラメータ・メタデータ

10.1.0

10.1.0

10.1.0

JDBC 3.0名前によるストアド・プロシージャ・パラメータの設定/取得

10.1.0

10.1.0

10.1.0

JDBC 3.0文プーリング

10.1.0

10.1.0

10.1.0

名前による文パラメータの設定

10.1.0

10.1.0

10.1.0

エンドツーエンドのトレース

10.1.0

10.1.0

Web RowSet

11.1

10.1.0

10.1.0

プロキシ認証

10.2.0

10.1.0

JDBC 3.0自動生成キー

10.2.0

10.2.0

JDBC 3.0保持可能カーソル

10.2.0

10.2.0

10.2.0

JDBC 3.0ローカル・トランザクションとグローバル・トランザクションの切替え

9.2.0

9.2.0

9.2.0

実行時接続ロード・バランシング

N/A

10.2.0

10.2.0

LOB用のsetXXXおよびgetXXXの拡張

10.2.0

10.2.0

XA接続キャッシュ

N/A

10.2.0

10.2.0

DML RETURNING

10.2.0

10.2.0

JSR 114 RowSet

10.2.0

10.2.0

SSL暗号化

9.2.0

10.2.0

SSL認証

9.2.0

11.1

JDK 1.5

11.1

11.1

11.1

JDK 1.6

11.1

11.1

JDBC 4.0

11.1

11.1

AES暗号化

11.1

SHA1ハッシュ

11.1

RADIUS認証

10.2.0

11.1

Kerberos認証

11.1

ANYDATAおよびANYTYPE型

11.1

11.1

ネイティブAQ

11.1

データベース変更通知

11.1

11.1

データベースの起動と停止

N/A

11.1

11.1

データ型のファクトリ・メソッド

11.1

11.1

11.1

バッファ・キャッシュ

11.1

11.1

11.1

セキュア・ファイル

11.1

11.1

11.1

診断機能

11.1

11.1

11.1

OCIクライアント結果キャッシュ

11.1.0

サーバー結果キャッシュ

11.1

11.1.0

11.1.0

ユニバーサル接続プール

11.1.0.7.0

11.1.0.7.0

TimeZoneのパッチ

11.2

11.2

セキュアなLobのサポート

11.2

11.2

LOBプリフェッチのサポート

11.2

11.2

ネットワーク接続プール

11.2

列セキュリティのサポート

11.2

XML型のキューのサポート(AQ)

11.2

通知グループ(AQとDCN)

11.2

SimpleFAN

11.2

11.2

注意:

- この表で、N/Aは、対応するOracle JDBCドライバにその機能が当てはまらないことを示します。

- ConnectionCacheImpl接続キャッシュ機能はOracle Database 10g以降非推奨となり、暗黙的接続キャッシュがこれにかわります。

2 スタート・ガイド

この章では、Oracle Java Database Connectivity(JDBC)ドライバ・バージョン、データベース・バージョンおよびJava Development Kit(JDK)バージョン間の互換性について説明します。また、クライアント・インストールと構成のテスト、および簡単なアプリケーションの実行方法の基本を説明します。この章の内容は次のとおりです。

- Oracle JDBCドライバのバージョン互換性

- JDBCクライアント・インストールの検証

- JDBCでの基本的な処理

- サンプル: 接続、問合せおよび結果処理

- JDBCプログラムでのストアド・プロシージャ・コール

- SQL例外の処理

Oracle JDBCドライバのバージョン互換性

この項では、一般的なJDBCバージョンの互換性について説明します。

下位互換性

JDBCドライバは、現在サポートされているバージョンのOracle Databaseで動作することが確認されています。たとえば、Oracle Database 11gリリース2(11.2)JDBC Thinドライバは、Oracle Databaseリリース10.2.x、10.1.x、9.2.xおよび9.0.1.xで動作します。ただし、8.0.xおよび7.xなどの旧リリースですでにサポート期間が終了しているデータベース・リリースへの接続はサポートしません。

上位互換性

既存のサポートされているJDBCドライバは、Oracle Database 11gリリース2(11.2)で動作することが確認されています。

注意:

- Oracle Database 11gリリース2(11.2)では、Oracle JDBCドライバでJDK 1.4.x以前のバージョンはサポートされなくなりました。

- サポート対象データベースの完全な、最新リストは、http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.htmlにあります。

JDBCクライアント・インストールの検証

JDBCクライアント・インストールを検証するには、次の操作をすべて実行する必要があります。

- インストールされたディレクトリとファイルの確認

- 環境変数の確認

- Javaコードのコンパイルと実行の確認

- JDBCドライバのバージョンの確認

- JDBCおよびデータベース接続のテスト

Oracle JDBCドライバのインストールは、プラットフォームによって異なります。プラットフォーム固有の情報が記載されたマニュアルの、ドライバのインストール手順に従ってください。

この項では、選択したドライバのインストールが完了しているものとして、JDBCドライバのOracleクライアントのインストールを検証する手順を説明します。

JDBC Thinドライバのインストールを行った場合は、クライアント・コンピュータにその他のインストールは必要ありません。

注意:
JDBC Thinドライバでは、データベースがインストールされているコンピュータ上にTCP/IPリスナーが必要です。

JDBC Oracle Call Interface(OCI)ドライバのインストールを行った場合は、Oracleクライアント・ソフトウェアもインストールする必要があります。これには、Oracle NetおよびOCIライブラリが含まれます。

インストールされたディレクトリとファイルの確認

Oracle Java製品をインストールすると、次のディレクトリが作成されます。

- ORACLE_HOME/jdbc

- ORACLE_HOME /jlib

次のディレクトリおよびファイルがORACLE_HOME/jdbcディレクトリに作成および格納されているかどうかを確認してください。

- demo
このディレクトリには、圧縮ファイルdemo.zipまたはdemo.tarが格納されています。この圧縮ファイルを解凍すると、samplesディレクトリおよびSamples-Readme.txtファイルが作成されます。samplesディレクトリには、JDBCエスケープ構文とOracle SQLの構文、PL/SQLブロック、ストリーム、ユーザー定義型、追加Oracle型拡張機能、Oracleパフォーマンス拡張機能の使用方法の例などのサンプル・プログラムが格納されています。

- doc
このディレクトリには、Oracle JDBC Application Program Interface(API)のドキュメントであるjavadoc.zipファイルが格納されています。

- lib
libディレクトリには、次のような必須Javaクラスが格納されています。

- orai18n.jarおよびorai18n-mapping.jar
グローバリゼーション用およびマルチバイト・キャラクタ・セット・サポート用のクラスが含まれています。

- ojdbc5.jar、ojdbc5_g.jar、ojdbc6.jarおよびojdbc6_g.jar
JDK 1.5およびJDK 1.6で使用するためのJDBCドライバ・クラスが含まれています。

注意:

- Oracle Database 11gリリース1(11.1)では、バージョン1.5より前のバージョンのJDKはサポートされていません。また、ojdbc14.jarファイルおよびclasses12.jarファイルも含まれていません。かわりに、Oracle Database 11gに含まれているojdbc5.jarファイルおよびojdbc6.jarファイルを使用できます。

- JSE 6以降を使用している場合は、明示的にJDBCドライバをロードする必要はありません。これは、Javaランタイムが必要に応じてドライバをロードすること、そのためClass.forName("oracle.jdbc.OracleDriver")やnew oracle.jdbc.OracleDriver()をコードに含める必要がないことを意味します。ただし、J2SE 5.0を使用する場合は、JDBCドライバを明示的にロードする必要があります。

- Readme.txt
製品の他のドキュメントで説明されていない、ドライバに関するリリース固有の最新情報が記載されています。

次のディレクトリがORACLE_HOME /jlibディレクトリに作成され、ファイルが格納されているかどうか確認してください。

- jta.jarおよびjndi.jar
これらのファイルには、Java Transaction API(JTA)とJava Naming and Directory Interface(JNDI)のためのクラスが含まれています。これらのファイルが必要になるのは、分散トランザクション管理のためのJTA機能、またはネーミング・サービスのためのJNDI機能を使用する場合のみです。

注意:
Sun社のWebサイトからもこれらのファイルを入手できます。しかし、Oracleドライバでテスト済のOracle提供のバージョンを使用することをお薦めします。

- ons.jar
このJARファイルには、Oracle Notification Servicesのクラスが含まれています。このファイルは、高速アプリケーション通知(FAN)を使用して、他のプロセスに構成やサービス・レベルの情報について通知する場合に必要です。

環境変数の確認

この項では、主にSun Solaris、LinuxおよびMicrosoft Windowsプラットフォームに関して、JDBC OCIドライバとJDBC Thinドライバのために設定する必要がある環境変数について説明します。

インストールしたJDBC OCIまたはThinドライバ用のCLASSPATH環境変数を設定する必要があります。CLASSPATH環境変数には次のものを含めます。

ORACLE_HOME/jdbc/lib/ojdbc5.jar
ORACLE_HOME/jlib/orai18n.jar

注意:
JTA機能およびJNDI機能を使用する場合は、jta.jarとjndi.jarもCLASSPATH環境変数に指定する必要があります。

JDBC OCIドライバ

JDBC OCIドライバをインストールする場合は、ライブラリ・パス環境変数に次の値を設定する必要もあります。

- Sun SolarisまたはLinuxの場合は、LD_LIBRARY_PATH環境変数を次のように設定します。

ORACLE_HOME/lib

このディレクトリには、libocijdbc11.so共有オブジェクト・ライブラリが格納されます。

注意:
64ビットのクライアントまたはデータベースに対して32ビットのJava仮想マシン(JVM)を動作させる場合は、ORACLE_HOME/lib32もLD_LIBRARY_PATH環境変数に追加する必要があります。

- Microsoft Windowsでは、次のようにPATH環境変数を設定します。

ORACLE_HOME\bin

このディレクトリには、ocijdbc11.dll動的リンク・ライブラリが格納されます。

ライブラリ・パス環境変数にJDBC OCI Instant Clientデータ共有ライブラリを指定すると、すべてのJDBC OCIデモ用プログラムをInstant Clientモードで実行できます。

関連項目:
第6章「JDBC OCIドライバ固有の機能」

JDBC Thinドライバ

JDBC Thinドライバをインストールする場合は、他の環境変数を指定する必要はありません。ただし、JDBCサーバー側Thinドライバを使用するには、許可を設定する必要があります。

サーバー側Thinドライバの許可の設定

JDBCサーバー側Thinドライバは、データベースへの接続用のソケットをオープンします。Oracle DatabaseではJavaセキュリティ・モデルを施行しているため、SocketPermissionオブジェクトについてチェックが実行されます。

JDBCサーバー側Thinドライバを使用するには、接続するユーザーに適切な許可を付与する必要があります。次の例は、ユーザーSCOTTに許可を付与する方法を示しています。

CREATE ROLE jdbcthin;
CALL dbms_java.grant_permission('JDBCTHIN', 'java.net.SocketPermission', '*', 'connect');
GRANT jdbcthin TO SCOTT;

grant_permissionコールのJDBCTHINは大文字で指定する必要があることに注意してください。アスタリスク(*)はパターンです。特定のコンピュータまたはポートのみに接続する許可を付与してユーザーへの許可を制限できます。

関連項目:
『Oracle Database Java開発者ガイド』

Javaコードのコンパイルと実行の確認

Javaがクライアント・システムで正しく設定されたことを確認するには、ORACLE_HOME/jdbc/demoの下のsamplesディレクトリに移動します。次に、コマンドラインで次のコマンドを順に入力して、JavaコンパイラおよびJavaインタプリタがエラーなく実行されていることを確認します。

javac

java

これらの各コマンドは、オプションとパラメータのリストを表示して終了します。可能であれば、jdbc/demo/samples/generic/SelectExampleなどの簡単なテスト・プログラムを使用して、コンパイルと実行の確認をしてください。

JDBCドライバのバージョンの確認

インストールしたJDBCドライバのバージョンを確認するには、OracleDatabaseMetaDataクラスのgetDriverVersionメソッドをコールします。

次のサンプル・コードは、ドライバのバージョンを確認する方法を示しています。

import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;

class JDBCVersion
{
public static void main (String args[]) throws SQLException
{
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:scott/tiger@<host>:<port>:<service>");
Connection conn = ods.getConnection();

// Create Oracle DatabaseMetaData object
DatabaseMetaData meta = conn.getMetaData();

// gets driver info:
System.out.println("JDBC driver version is " + meta.getDriverVersion());
}
}

次のコマンドを実行すると、JDBCドライバのバージョンを確認できます。

- java -jar ojdbc5.jar

- java -jar ojdbc6.jar

JDBCおよびデータベース接続のテスト

samplesディレクトリには、特定のOracle JDBCドライバ用のサンプル・プログラムが格納されています。その1つであるJdbcCheckup.javaは、JDBCおよびデータベース接続のテスト用です。このプログラムには、ユーザー名、パスワードおよび接続するデータベース名の入力が必要です。このプログラムは、データベースに接続し、「Hello World」という文字列の問合せを行い、それを画面に出力します。

samplesディレクトリでJdbcCheckup.javaプログラムをコンパイルして実行します。問合せの結果の画面出力でエラーが発生しなければ、JavaおよびJDBCは正しくインストールされています。

JdbcCheckup.javaは簡単なプログラムですが、次の操作を実行することにより、いくつかの重要な機能を示します。

- JDBCクラスを含む、必要なJavaクラスのインポート

- DataSourceインスタンスの作成

- データベースへの接続

- 単純な問合せの実行

- 問合せ結果の画面への出力

JDBC OCIドライバを使用するJdbcCheckup.javaプログラムは次のとおりです。

/*
* This sample can be used to check the JDBC installation.
* Just run it and provide the connect information. It will select
* "Hello World" from the database.
*/

// You need to import the java.sql and JDBC packages to use JDBC
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;

// We import java.io to be able to read from the command line
import java.io.*;

class JdbcCheckup
{
public static void main(String args[]) throws SQLException, IOException
{

// Prompt the user for connect information
System.out.println("Please enter information to test connection to
the database");
String user;
String password;
String database;

user = readEntry("user: ");
int slash_index = user.indexOf('/');
if (slash_index != -1)
{
password = user.substring(slash_index + 1);
user = user.substring(0, slash_index);
}
else
password = readEntry("password: ");
database = readEntry("database(a TNSNAME entry): ");

System.out.print("Connecting to the database...");
System.out.flush();
System.out.println("Connecting...");
// Open an OracleDataSource and get a connection
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@" + database);
ods.setUser(user);
ods.setPassword(password);
Connection conn = ods.getConnection();
System.out.println("connected.");

// Create a statement
Statement stmt = conn.createStatement();

// Do the SQL "Hello World" thing
ResultSet rset = stmt.executeQuery("select 'Hello World' from dual");

while (rset.next())
System.out.println(rset.getString(1));
// close the result set, the statement and the connection
rset.close();
stmt.close();
conn.close();
System.out.println("Your JDBC installation is correct.");
}

// Utility function to read a line from standard input
static String readEntry(String prompt)
{
try
{
StringBuffer buffer = new StringBuffer();
System.out.print(prompt);
System.out.flush();
int c = System.in.read();
while (c != '\n' && c != -1)
{
buffer.append((char)c);
c = System.in.read();
}
return buffer.toString().trim();
}
catch(IOException e)
{
return "";
}
}
}

JDBCでの基本的な処理

JDBCクライアント・インストールの検証が完了すると、JDBCアプリケーションの作成を開始できます。Oracle JDBCドライバを使用する場合は、プログラムに特定のドライバ固有情報を含める必要があります。この項では、ドライバ固有情報の追加場所と追加方法について、チュートリアルの形式で説明します。チュートリアルは、クライアントからデータベースへの接続および問合せを行うコードを作成する方法を、手順を追って説明します。

次のタスクを実行するコードを記述する必要があります。

1. パッケージのインポート

2. データベースへの接続のオープン

3. Statementオブジェクトの作成

4. 問合せの実行と結果セット・オブジェクトの取出し

5. 結果セット・オブジェクトの処理

6. 結果セット・オブジェクトとStatementオブジェクトのクローズ

7. データベースの変更

8. 変更のコミット

9. 接続のクローズ

注意:
最初の3つのタスク用のOracleドライバ固有情報を指定して、プログラムがJDBC Application Program Interface(API)を使用してデータベースにアクセスできるようにします。その他のタスクについては、Javaアプリケーションの場合と同様に、標準JDBC Javaコードを使用できます。

パッケージのインポート

使用するOracle JDBCドライバの種類にかかわらず、表2-1に示されているimport文をプログラムの最初に記述する必要があります。

表2-1 JDBCドライバ用のimport文

import文

提供パッケージ

import java.sql.*;

標準のJDBCパッケージ

import java.math.*;

BigDecimalクラスおよびBigIntegerクラス。アプリケーションでこれらのクラスを使用しない場合は、このパッケージを省略できます。

import oracle.jdbc.*;

import oracle.jdbc.pool.*;

import oracle.sql.*;

JDBCに対するOracleの拡張機能。これはオプションです。

OracleDataSource

Oracle型拡張機能。これはオプションです。

オプションとなっているOracleパッケージは、Oracle JDBCドライバの拡張機能へのアクセスを提供しますが、この項の例には必要ありません。

注意:
ワイルド・カードのアスタリスク(*)は使用せずに、アプリケーションに必要なクラスのみをインポートすることをお薦めします。このガイドでは簡単にするためにアスタリスク(*)を使用していますが、クラスおよびインタフェースのインポート方法としてはお薦めしません。

データベースへの接続のオープン

最初に、OracleDataSourceインスタンスを作成する必要があります。次に、OracleDataSource.getConnectionメソッドを使用してデータベースへの接続をオープンします。取り出した接続のプロパティは、OracleDataSourceインスタンスから導出されたものです。URL接続プロパティを設定した場合は、TNSEntryName、DatabaseName、ServiceName、ServerName、PortNumber、Network Protocolおよびドライバのタイプを含む他のプロパティはすべて無視されます。

データベースURL、ユーザー名およびパスワードの指定

次のコードは、データソースのURL、ユーザー名およびパスワードを設定します。

OracleDataSource ods = new OracleDataSource();
ods.setURL(url);
ods.setUser(user);
ods.setPassword(password);

次の例では、JDBC Thinドライバを使用して、パスワードがtigerのユーザーscottを、サービス名がorclのデータベースに、ホストmyhostのポート1521経由で接続します。

OracleDataSource ods = new OracleDataSource();
String url = "jdbc:oracle:thin:@//myhost:1521/orcl",
ods.setURL(url);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

注意:
引数で指定されたユーザー名とパスワードは、URLで指定されたユーザー名とパスワードをオーバーライドします。

ユーザー名とパスワードを含むデータベースURLの指定

次の例では、JDBC Oracle Call Interface(OCI)ドライバを使用して、パスワードがtigerのユーザーscottを、Transparent Network Substrate(TNS)エントリがmyTNSEntryであるデータベース・ホストに接続します。この場合、URLは、ユーザー名とパスワードを含む、唯一の入力パラメータです。

String url = "jdbc:oracle:oci:scott/tiger@myTNSEntry");
ods.setURL(url);
Connection conn = ods.getConnection();

Thinドライバを使用して接続する場合は、ポート番号を指定する必要があります。たとえば、ポート1521上にTCP/IPリスナーを持つホストmyhost上のデータベースに接続し、サービス識別子がorclである場合は、次のようなコードを記述します。

String URL = "jdbc:oracle:thin:scott/tiger@//myhost:1521/orcl");
ods.setURL(URL);
Connection conn = ods.getConnection();

関連項目:
第8章「データソースおよびURL」

Statementオブジェクトの作成

データベースに接続し、そのプロセスでConnectionオブジェクトを作成した後、次に、Statementオブジェクトを作成します。JDBC ConnectionオブジェクトのcreateStatementメソッドは、JDBC Statement型のオブジェクトを返します。前の項の、Connectionオブジェクトconnが作成された例の続きとして、Statementオブジェクトを作成する方法の例を示します。

Statement stmt = conn.createStatement();

問合せの実行と結果セット・オブジェクトの取出し

データベースへの問合せを行う場合、StatementオブジェクトのexecuteQueryメソッドを使用します。このメソッドは、入力としてSQL文を受け取り、JDBC ResultSetオブジェクトを戻します。

注意:

- Statementオブジェクトを実行するために使用されるメソッドは、実行されているSQL文の種類により異なります。StatementオブジェクトがResultSetオブジェクトを戻すSQL問合せを表している場合は、executeQueryメソッドを使用します。SQLが更新件数を戻すDDL文またはDML文の場合は、executeUpdateメソッドを使用します。SQL文の種類がわからない場合は、executeメソッドを使用します。

- 標準JDBCドライバの場合、実行されているSQL文字列がResultSetオブジェクトを戻さないと、executeQueryメソッドでSQLException例外がスローされます。Oracle JDBCドライバの場合、実行されているSQL文字列がResultSetオブジェクトを戻さなくても、executeQueryメソッドでSQLException例外はスローされません。

この例のStatementオブジェクトstmt作成後の次の処理は、問合せを実行し、EMPという従業員の表のename列の内容が含まれたResultSetオブジェクトを戻すことです。

ResultSet rset = stmt.executeQuery ("SELECT ename FROM emp");

結果セット・オブジェクトの処理

問合せの実行後は、ResultSetオブジェクトのnext()メソッドを使用して結果を反復します。このメソッドは、結果セットを行ごとに進み、結果セットの最後に達するとそれを検出します。

結果セット内を反復しながらデータを引き出すには、ResultSetオブジェクトの適切なgetXXXメソッドを使用します。このXXXには、Javaのデータ型が対応します。

たとえば、次のコードは、以前の項のResultSetオブジェクトrset内を反復して、各従業員名の取出しおよび出力を行います。

while (rset.next())
System.out.println (rset.getString(1));

next()メソッドは、結果セットの最後に達するとfalseを戻します。従業員名は、Java String値として実体化されます。

結果セット・オブジェクトとStatementオブジェクトのクローズ

ResultSetとStatementオブジェクトの使用後に、明示的にこれらをクローズする必要があります。これは、Oracle JDBCドライバの使用時に作成した、すべてのResultSetおよびStatementオブジェクトに適用されます。ドライバには、ファイナライザ・メソッドがありません。クリーン・アップ・ルーチンは、ResultSetおよびStatementクラスのcloseメソッドで実行されます。明示的にResultSetおよびStatementオブジェクトをクローズしないと、深刻なメモリー・リークが発生する場合があります。また、データベースのカーソルが不足します。結果セットと文の両方をクローズすると、データベース内の対応するカーソルが解放されます。結果セットのみをクローズすると、カーソルは解放されません。

たとえば、ResultSetオブジェクトがrsetで、Statementオブジェクトがstmtの場合は、次のコードの行を使用して結果セットと文をクローズできます。

rset.close();
stmt.close();

指定したConnectionオブジェクトが作成するStatementオブジェクトをクローズする場合、接続自体はオープンしたままになります。

注意:
一般に、close文はfinally句に書き込みます。

データベースの変更

DML操作

INSERT操作またはUPDATE操作などのDML(データ操作言語)操作を実行するには、StatementオブジェクトまたはPreparedStatementオブジェクトのいずれかを作成します。PreparedStatementオブジェクトによって、様々な入力パラメータのセットで文を実行できます。JDBC ConnectionオブジェクトのprepareStatementメソッドを使用すると、様々なバインド・パラメータを取り、文定義でJDBC PreparedStatementオブジェクトを戻す文を定義できます。

データベースに送信するプリコンパイルされたSQL文にデータをバインドするには、PreparedStatementでsetXXXメソッドを使用します。

関連項目:
「setObjectメソッドとsetOracleObjectメソッド」および「他のsetXXXメソッド」

次の例では、プリコンパイルされたSQL文を使用して、EMP表に2行を追加するINSERT操作を実行する方法を示します。

// Prepare to insert new names in the EMP table
PreparedStatement pstmt = null;
try{
pstmt = conn.prepareStatement ("insert into EMP (EMPNO, ENAME) values (?, ?)");

// Add LESLIE as employee number 1500
pstmt.setInt (1, 1500);          // The first ? is for EMPNO
pstmt.setString (2, "LESLIE");   // The second ? is for ENAME
// Do the insertion
pstmt.execute ();

// Add MARSHA as employee number 507
pstmt.setInt (1, 507);           // The first ? is for EMPNO
pstmt.setString (2, "MARSHA");   // The second ? is for ENAME
// Do the insertion
pstmt.execute ();
}

finally{
if(pstmt!=null)

// Close the statement
pstmt.close();
}

DDL操作

データ定義言語(DDL)操作を実行するには、StatementオブジェクトまたはPreparedStatementオブジェクトのいずれかを作成します。次の例では、Statementオブジェクトを使用してデータベースに表を作成する方法を示しています。

//create table EMP with columns EMPNO and ENAME
String query;
Statement stmt=null;

try{
query="create table EMP " +
"(EMPNO int, " +
"ENAME varchar(50))";
stmt = conn.createStatement();
stmt.executeUpdate(query);
}
finally{
//close the Statement object
stmt.close();
}

コードでDDL操作の再実行が必要な場合は、文を再実行する前に、その文をもう一度準備する必要があります。次の例では、再実行の前にDDL文を準備する方法を示しています。

//
PreparedStatement pstmt = null;
PreparedStatement tstmt = null;
try{
pstmt = conn.prepareStatement ("insert into EMP (EMPNO, ENAME) values (?, ?)");

// Add LESLIE as employee number 1500
pstmt.setInt (1, 1500);          // The first ? is for EMPNO
pstmt.setString (2, "LESLIE");   // The second ? is for ENAME
// Do the insertion
pstmt.execute ();

tstmt = conn.prepareStatement("truncate table EMP");
tstmt.executeUpdate();

// Add MARSHA as employee number 507
pstmt.setInt (1, 507);           // The first ? is for EMPNO
pstmt.setString (2, "MARSHA");   // The second ? is for ENAME
// Do the insertion
pstmt.execute ();

tstmt.close();
tstmt = conn.prepareStatement("truncate table EMP");
tstmt.executeUpdate();
}
finally{
if(pstmt!=null)

// Close the statement
pstmt.close();
}

変更のコミット

デフォルトでは、データ操作言語(DML)操作は実行時に自動的にコミットされます。これは自動コミット・モードともいいます。ただし、Connectionオブジェクトでの次のメソッドのコールによって、自動コミット・モードを無効にできます。

conn.setAutoCommit(false);

関連項目:
「自動コミット・モードの無効化」

自動コミット・モードを無効にした場合は、Connectionオブジェクトで適切なメソッドをコールして、変更を手動でコミットするか、ロールバックする必要があります。

conn.commit();

または

conn.rollback();

COMMIT操作またはROLLBACK操作は、直前のCOMMITまたはROLLBACK以降に実行されたすべてのDML文に影響を与えます。

注意:

- 自動コミット・モードを無効にして、直前の変更を明示的にコミットまたはロールバックせずに接続をクローズした場合は、暗黙的なCOMMIT操作が実行されます。

- すべてのデータ定義言語(DDL)操作には、常に暗黙的なCOMMITが含まれます。自動コミット・モードを無効にした場合、この暗黙的なCOMMITは、まだ明示的にコミットまたはロールバックされていない保留DML文もコミットします。

コミット動作の変更

トランザクションによりデータベースを更新すると、この更新に対応するREDOエントリが生成されます。Oracle Databaseでは、トランザクションの完了まで、このREDOを一時的にメモリーに保存します。トランザクションをコミットすると、ログ・ライター(LGWR)プロセスによりコミットのREDOエントリが、そのトランザクションにおけるすべての変更について累積したREDOエントリとともに、ディスクに書き込まれます。デフォルトでは、Oracle Databaseは、コールがクライアントに戻る前にREDOをディスクに書き込みます。アプリケーションはREDOエントリがディスクに保存されるまで待つ必要があるため、この動作によりコミットに待機時間が生じます。

アプリケーションに非常に高いトランザクション・スループットが必要で、コミット待機時間を短縮するためにコミットの永続性を犠牲にしてもよいという場合は、アプリケーションの必要に応じて、デフォルトのCOMMIT操作の動作を変更できます。COMMIT操作の動作は、次のオプションにより変更できます。

- WAIT

- NOWAIT

- WRITEBATCH

- WRITEIMMED

関連項目:
これらのオプションの詳細は、次のWebサイトにあるOracle Javadocを参照してください。

http://download.oracle.com/otn/utilities_drivers/jdbc/111060/doc/javadoc/index.html

これらのオプションを指定すると、コミット段階の2つの異なる面を制御できます。

- COMMITコールが、サーバーによって処理されるまで待機するかどうか。これには、WAITオプションまたはNOWAITオプションを使用します。

- ログ・ライターがコールをバッチ処理するかどうか。これには、WRITEIMMEDオプションまたはWRITEBATCHオプションを使用します。

異なるオプションを組み合せることもできます。たとえば、COMMITコールがサーバーによる処理を待たずに戻り、ログ・ライターがコミットをバッチ処理するようにするには、NOWAITオプションとWRITEBATCHオプションを一緒に使用します。たとえば、次のようになります。

((OracleConnection)conn).commit(
EnumSet.of(
OracleConnection.CommitOption.WRITEBATCH,
OracleConnection.CommitOption.NOWAIT));

注意:
WAITオプションとNOWAITオプションは、逆の意味を持つため、一緒に使用できません。一緒に使用すると、JDBCドライバは例外をスローします。同じことが、WRITEIMMEDオプションとWRITEBATCHオプションにも当てはまります。

接続のクローズ

必要な操作をすべて実行し、接続が不要になった後に、データベースへの接続をクローズする必要があります。次のように、Connectionオブジェクトのcloseメソッドを使用してクローズできます。

conn.close();

注意:
一般に、close文はfinally句に書き込みます。

サンプル: 接続、問合せおよび結果処理

次の例は、前の項で説明した処理を例証するものです。Oracle JDBC Thinドライバを使用してデータソースを作成し、データベースに接続し、Statementオブジェクトを作成して問合せを実行し、結果セットを処理します。

Statementオブジェクトの作成、問合せの実行、ResultSetの戻りと処理、および文と接続のクローズを行うコードは、標準JDBC APIを使用していることに注意してください。

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import oracle.jdbc.pool.OracleDataSource;

class JdbcTest
{
public static void main (String args []) throws SQLException
{

OracleDataSource ods = null;
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;

// Create DataSource and connect to the local database
ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@//myhost:1521/orcl");
ods.setUser("scott");
ods.setPassword("tiger");
conn = ods.getConnection();

try
{
// Query the employee names
stmt = conn.createStatement ();
rset = stmt.executeQuery ("SELECT ename FROM emp");

// Print the name out
while (rset.next ())
System.out.println (rset.getString (1));
}

//Close the result set, statement, and the connection

finally{
if(rset!=null) rset.close();
if(stmt!=null) stmt.close();
if(conn!=null) conn.close();
}
}
}

OCIドライバ用のコードを利用する場合は、OracleDataSource.setURLメソッドのコールを次の文で置き換えます。

ods.setURL("jdbc:oracle:oci:@MyHostString");

MyHostStringには、TNSNAMES.ORAファイル内のエントリを指定します。

JDBCプログラムでのストアド・プロシージャ・コール

この項では、Oracle JDBCドライバが次の種類のストアド・プロシージャをサポートする方法について説明します。

- PL/SQLストアド・プロシージャ

- Javaストアド・プロシージャ

PL/SQLストアド・プロシージャ

Oracle JDBCドライバは、PL/SQLストアド・プロシージャおよび無名ブロックの処理をサポートします。このドライバは、PL/SQLブロック構文とほとんどのJDBCエスケープ構文をサポートします。次のPL/SQLコールは、任意のOracle JDBCドライバで使用できます。

// JDBC escape syntax
CallableStatement cs1 = conn.prepareCall
( "{call proc (?,?)}" ) ; // stored proc
CallableStatement cs2 = conn.prepareCall
( "{? = call func (?,?)}" ) ; // stored func
// PL/SQL block syntax
CallableStatement cs3 = conn.prepareCall
( "begin proc (?,?); end;" ) ; // stored proc
CallableStatement cs4 = conn.prepareCall
( "begin ? := func(?,?); end;" ) ; // stored func

Oracle構文の使用例として、ここでは、ストアド・ファンクションを作成するPL/SQLコードの一部を使用します。PL/SQLファンクションは、文字列を取得し、それに接尾辞を連結します。

create or replace function foo (val1 char)
return char as
begin
return val1 || 'suffix';
end;

JDBCプログラム内のファンクションの起動は、次のようになります。

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@<hoststring>");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

CallableStatement cs = conn.prepareCall ("begin ? := foo(?); end;");
cs.registerOutParameter(1,Types.CHAR);
cs.setString(2, "aa");
cs.executeUpdate();
String result = cs.getString(1);

Javaストアド・プロシージャ

JDBCを使用して、SQLおよびPL/SQLエンジン経由でJavaストアド・プロシージャをコールできます。Javaストアド・プロシージャをコールするための構文は、正しく公開されていると仮定すると、PL/SQLストアド・プロシージャをコールするための構文と同じです。正しく公開されているとは、つまり、Oracleデータ・ディクショナリに公開するためのコール仕様を記述していることを意味します。アプリケーションでJavaネイティブ・インタフェースを使用してJavaストアド・プロシージャをコールすると、static Javaメソッドを直接起動できます。

SQL例外の処理

エラー状況を処理するために、Oracle JDBCドライバはSQL例外をスローし、java.sql.SQLExceptionクラスまたはそのサブクラスのインスタンスを作成します。エラーはJDBCドライバまたはデータベース自体のいずれかで発生する可能性があります。表示されるメッセージには、エラーおよびエラーを発行したメソッドの説明が含まれます。ランタイム情報が追加されることもあります。

JDBC 3.0では、SQLExceptionという単一の例外しかサポートされていません。ただし、エラーはカテゴリが多いので、区別すると便利です。そのため、JDBC 4.0では様々なカテゴリのエラーを特定するためにSQLException例外の一連のサブクラスが導入されています。この機能の詳細は、「JDBC 4.0標準のサポート」を参照してください。

基本例外処理には、エラー・メッセージの取出し、エラー・コードの取出し、SQL状態の取出しおよびスタック・トレースの出力が含まれます。SQLExceptionクラスには、使用可能な場合にこのようなすべての情報を取り出す機能があります。

関連項目:

- 付録D「JDBCエラー・メッセージ」

- 『Oracle Databaseエラー・メッセージ』

エラー情報の取出し

SQLExceptionクラスの次のメソッドで、基本エラー情報を取り出すことができます。

- getMessage

- getErrorCode

- getSQLState

次の例はgetMessage()メソッド・コールからの情報を出力します。

catch(SQLException e)
{
System.out.println("exception: " + e.getMessage());
}

これはJDBCドライバで発生したエラーに対して、次のような情報を出力します。

exception: Invalid column type

注意:
Oracleでサポートされている言語とキャラクタ・セットでエラー・メッセージ・テキストを使用できます。

スタック・トレースの出力

SQLExceptionクラスには、スタック・トレースを出力するためのprintStackTrace()メソッドがあります。このメソッドは、スロー可能なオブジェクトのスタック・トレースを標準エラー・ストリームに出力します。出力のために、java.io.PrintStreamオブジェクトまたはjava.io.PrintWriterオブジェクトも指定できます。

次のコード・フラグメントは、SQLの例外を捕捉してスタック・トレースを表示する方法を示しています。

try { <some code> }
catch(SQLException e) { e.printStackTrace (); }

JDBCドライバでエラーを処理する方法を説明するために、次のコードでは不適切な列索引を使用していると仮定します。

// Iterate through the result and print the employee names
// of the code

try {
while (rset.next ())
System.out.println (rset.getString (5));  // incorrect column index
}
catch(SQLException e) { e.printStackTrace (); }

列索引が不適切であると仮定すると、このプログラムの実行によって次のエラー・テキストが生成されます。

java.sql.SQLException: Invalid column index
at oracle.jdbc.driver.OracleResultSetImpl.getDate(OracleResultSetImpl.java:1556)
at Employee.main(Employee.java:41)

第II部

Oracle JDBC

第II部では、Oracle Database 11gでサポートされている様々なバージョンのJava Database Connectivity(JDBC)について説明します。JDBC Thinドライバ、JDBC Oracle Call Interface(OCI)ドライバおよびサーバー側内部ドライバに固有の機能についても説明します。

第II部の構成は次のとおりです。

- 第3章「JDBC標準のサポート」

- 第4章「Oracle拡張機能」

- 第5章「JDBC Thin固有の機能」

- 第6章「JDBC OCIドライバ固有の機能」

- 第7章「サーバー側内部ドライバ」

3 JDBC標準のサポート

Oracle Java Database Connectivity(JDBC)ドライバは、様々なバージョンのJDBC標準機能をサポートしています。Oracle Database 11gリリース2(11.2)では、Oracle JDBCドライバが強化され、JDBC 4.0標準がサポートされました。これらの機能は、oracle.jdbcパッケージとoracle.sqlパッケージによって提供されます。これらのパッケージでは、Java Development Kit(JDK)リリース1.5と1.6がサポートされています。この章では、Oracle JDBCドライバでのJDBC標準のサポートについて説明します。この章には次の項目があります。

- JDBC 2.0標準のサポート

- JDBC 3.0標準のサポート

- JDBC 4.0標準のサポート

JDBC 2.0標準のサポート

標準のJDBC 2.0の機能は、JDK 1.2以降のバージョンでサポートされています。考慮すべき点が3つあります。

- オブジェクト、配列、ラージ・オブジェクト(LOB)などのデータ型に対するサポート。このサポートは、標準java.sqlパッケージを介して処理されます。

- 結果セット拡張やバッチ更新などの標準機能に対するサポート。このサポートは、JDK 1.2.x以上では、Connection、ResultSetおよびPreparedStatementなどの標準オブジェクトを介して処理されます。

- JDBC 2.0 Optional Packageの機能など、Standard Extension Application Program Interface(API)とも呼ばれる拡張機能に対するサポート。たとえばデータソース、接続プーリングおよび分散トランザクションなどがあげられます。

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

- データ型のサポート

- 標準機能のサポート

- 拡張機能のサポート

- JDBC2.0 Standard Extension APIとオラクル社独自のパフォーマンス強化API

注意:
1.5より前のJDKのバージョンは、もうサポートされていません。oracle.jdbc2パッケージは削除されました。

データ型のサポート

Oracle JDBCは、標準java.sqlパッケージ内のインタフェースの実装による標準JDBC 2.0機能を含む、JDK 1.5およびJDK 1.6を完全にサポートしています。これらのインタフェースは、oracle.sqlパッケージとoracle.jdbcパッケージ内のクラスによって、適宜実装されます。

標準機能のサポート

ojdbc5.jarのJDBCクラスを使用するJDK 1.5環境では、スクロール可能結果セット、更新可能結果セット、バッチ更新などのJDBC 2.0機能は、標準のJDBC 2.0インタフェースによって指定されたメソッドを介してサポートされます。

拡張機能のサポート

データソース、接続プーリングおよび分散トランザクションなどのJDBC 2.0 Optional Packageの各機能は、JDK 1.2.x以上の環境でサポートされます。

標準javax.sqlパッケージとそのインタフェースを実装するクラスは、Oracle Databaseでパッケージ化されたJavaアーカイブ(JAR)ファイルに格納されています。

JDBC2.0 Standard Extension APIとオラクル社独自のパフォーマンス強化API

以前はOracle拡張機能として提供されていた次のパフォーマンス拡張機能は、JDBC2.0で使用できます。

- バッチ更新

- フェッチ・サイズまたは行プリフェッチ

どちらの場合でも、標準モデルまたはOracleモデルを使用するオプションがあります。可能なかぎりJDBC標準モデルの使用をお薦めします。ただし、これらの機能のために、1つのアプリケーション内で標準モデルとOracleモデルを同時に使用しないでください。

関連項目:

- 「バッチ更新」

- 「フェッチ・サイズ」

JDBC 3.0標準のサポート

標準のJDBC 3.0の機能は、JDK 1.4以降のバージョンでサポートされています。表3-1では、Oracle Database 11gリリース2(11.2)でサポートしているJDBC 3.0機能と、各機能に関する詳細の参照先を示しています。

表3-1 JDBC 3.0機能の主な領域

機能

コメントと参照

トランザクション・セーブポイント

詳細は、「トランザクション・セーブポイント」を参照してください。

文キャッシュ

接続プーリングによってコンパイルされたSQL文を再使用します。第20章「文キャッシュと結果セット・キャッシュ」を参照してください。

ローカル・トランザクションとグローバル・トランザクションの切替え

「ローカル・トランザクションとグローバル・トランザクションの切替え」を参照してください。

LOBの変更

「JDBC 3.0のLOBインタフェース・メソッド」を参照してください。

名前付きSQLパラメータ

「インタフェースoracle.jdbc.OracleCallableStatement」および「インタフェースoracle.jdbc.OraclePreparedStatement」を参照してください。

RowSet

第18章「JDBC RowSet」を参照してください。

自動生成キーの取出し

「自動生成キーの取出し」を参照してください。

結果セットの保持機能

「結果セットの保持機能」を参照してください。

この項では、Oracle JDBCドライバによってサポートされている次のJDBC 3.0機能について説明します。

- トランザクション・セーブポイント

- 自動生成キーの取出し

- JDBC 3.0のLOBインタフェース・メソッド

- 結果セットの保持機能

トランザクション・セーブポイント

JDBC 3.0の仕様はセーブポイントをサポートしており、トランザクション内でより細かい境界設定をすることができます。アプリケーションはトランザクション内にセーブポイントを設定して、セーブポイントより後に行われたすべての作業をロールバックすることができます。セーブポイントを使用することで、トランザクションの原子性が緩和されます。セーブポイントを持つトランザクションは、トランザクションのコンテキスト外部では1つの単位のように見えるという点で原子的ですが、トランザクション内で動作しているコードは部分的な状態を維持することができます。

注意:
セーブポイントがサポートされるのは、ローカル・トランザクションのみです。グローバル・トランザクション内でセーブポイントを指定すると、SQLException例外が発生します。

セーブポイントの作成

セーブポイントを作成するには、java.sql.Savepointインスタンスを戻すConnection.setSavepointを使用します。

セーブポイントには名前がある場合とない場合があります。セーブポイントの名前を指定するには、setSavepointメソッドに文字列を指定します。名前が未指定の場合は、整数のIDが割り当てられます。名前の取出しにはgetSavepointNameメソッドを使用します。IDの取出しにはgetSavepointIdメソッドを使用します。

注意:
名前付けされていないセーブポイントから名前を取り出そうとしたり、名前付けされているセーブポイントからIDを取り出そうとしたりすると、SQLException例外がスローされます。

セーブポイントまでのロールバック

セーブポイントまでロールバックするには、Connection.rollback(Savepoint svpt)メソッドを使用します。解放されているセーブポイントまでロールバックしようとすると、SQLException例外がスローされます。

セーブポイントの解放

セーブポイントを削除するには、Connection.releaseSavepoint(Savepoint svpt)メソッドを使用します。

セーブポイント・サポートのチェック

使用中のデータベースでセーブポイントがサポートされているかどうかを調べるには、oracle.jdbc.OracleDatabaseMetaData.supportsSavepointsメソッドをコールします。セーブポイントが使用可能な場合はtrue、そうでない場合はfalseが戻されます。

セーブポイントに関する注意事項

セーブポイントを使用する場合は、次の点に注意する必要があります。

- セーブポイントの解放後、ロールバック操作でそのセーブポイントを参照しようとすると、SQLException例外がスローされます。

- トランザクションがコミットまたはロールバックされると、そのトランザクション内の作成済セーブポイントはすべて自動的に解放され、無効になります。

- あるセーブポイントまでトランザクションをロールバックすると、そのセーブポイントより後に作成されたセーブポイントはすべて自動的に解放され、無効になります。

自動生成キーの取出し

多くのデータベース・システムでは、行が挿入される際に一意のキー・フィールドが自動的に生成されます。Oracle Databaseでは、順序とトリガーにより、この機能が提供されます。JDBC 3.0には、自動生成キーの取出し機能が導入され、生成された値を取り出せるようになりました。JDBC 3.0では、自動生成キーの取出し機能をサポートするために、次のインタフェースが拡張されました。

- java.sql.DatabaseMetaData

- java.sql.Connection

- java.sql.Statement

これらのインタフェースには、自動生成キーの取出しをサポートするメソッドが用意されています。ただし、この機能はINSERT文が処理される場合にのみサポートされます。その他のデータ操作言語(DML)文の処理では、自動生成キーの取出しは実施されません。

注意:
Oracleのサーバー側内部ドライバでは、自動生成キーの取出し機能をサポートしていません。

java.sql.Statement

キー列を明示的に指定しないと、Oracle JDBCドライバでは取り出す列を特定できません。特定できるのは、列名または列索引の配列が使用されている場合です。ただし、int型のStatement.RETURN_GENERATED_KEYSフラグが使用されている場合、Oracle JDBCドライバではこれらの列を特定できません。int型フラグを使用して自動生成キーが戻るように指定した場合は、ROWID擬似列がキーとして戻ります。このROWIDは、ResultSetオブジェクトからフェッチして、他の列を取り出すために使用できます。

サンプル・コード

次のコードは、自動生成キーの取出しを示しています。

/** SQL statements for creating an ORDERS table and a sequence for generating the
* ORDER_ID.
*
* CREATE TABLE ORDERS (ORDER_ID NUMBER, CUSTOMER_ID NUMBER, ISBN NUMBER,
* DESCRIPTION NCHAR(5))
*
* CREATE SEQUENCE SEQ01 INCREMENT BY 1 START WITH 1000
*/

...
String cols[] = {"ORDER_ID", "DESCRIPTION"};

// Create a PreparedStatement for inserting a row into the ORDERS table.
OraclePreparedStatement pstmt = (OraclePreparedStatement)
conn.prepareStatement("INSERT INTO ORDERS (ORDER_ID, CUSTOMER_ID, ISBN,  DESCRIPTION) VALUES (SEQ01.NEXTVAL, 101,
966431502, ?)", cols);
char c[] = {'a', '\u5185', 'b'};
String s = new String(c);
pstmt.setNString(1, s);
pstmt.executeUpdate();
ResultSet rset = pstmt.getGeneratedKeys();
...

前の例では、シーケンス( SEQ01)がORDER_ID列の値を生成するために作成されます。値は、1000から始まり、シーケンスが処理されて次の値が生成されるたびに1ずつ増加します。OraclePreparedStatementオブジェクトは、ORDERS表に行を挿入するために作成されています。

制限事項

自動生成キーはDML RETURNING句を使用して実装されます。このため、次の制限事項があります。

- 自動生成キーとバッチ更新を組み合せることはできません。

- getGeneratedKeysメソッドから戻されるResultSetオブジェクトには位置によってのみアクセスする必要があります。ResultSetオブジェクトの列としてはバインド変数名を使用しないでください。

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

表3-2と表3-3では、Oracle独自のメソッドとJDBC 3.0標準メソッドとの間の変換を示しています。

表3-2 等価のBLOBメソッド

Oracle独自のメソッド

JDBC 3.0標準メソッド

putBytes(long pos, byte [ ] bytes)

setBytes(long pos, byte[] bytes)

putBytes(long pos, byte [ ] bytes, int length)

setBytes(long pos, byte[] bytes, int offset, int len)

getBinaryOutputStream(long pos)

setBinaryStream(long pos)

trim (long len)

truncate(long len)

表3-3 等価のCLOBメソッド

Oracle独自のメソッド

JDBC 3.0標準メソッド

putString(long pos, String str)

setString(long pos, String str)

該当なし

setString(long pos, String str, int offset, int len)

getAsciiOutputStream(long pos)

setAsciiStream(long pos)

getCharacterOutputStream(long pos)

setCharacterStream(long pos)

trim (long len)

truncate(long len)

結果セットの保持機能

結果セットの保持機能は、JDBC 3.0から導入されました。この機能は、コミット操作が実行されるとき、ResultSetオブジェクトがオープンされているべきか、クローズされているべきかをアプリケーションが判断できるようにします。コミット操作は暗黙的でも明示的でもかまいません。

Oracle Databaseでサポートしているのは、HOLD_CURSORS_OVER_COMMITのみです。したがって、これが、Oracle JDBCドライバのデフォルト値です。保持機能を変更しようとすると必ず、SQLException例外がスローされます。

JDBC 4.0標準のサポート

JDBC 4.0標準は、JDK 1.6以降のバージョンでサポートされています。Oracle Database 11gリリース2(11.2)のJDBCドライバでは、JDBC 4.0標準がサポートされています。

注意:

- JDBC 4.0を標準サポートするには、classpath環境変数でojdbc6.jarを指定しておく必要があります。

- JDBC 4.0仕様では、クライアント情報の取得と設定のために、getClientInfoとsetClientInfoメソッドが定義されています。11.2のOracle JDBCドライバは、いかなるクライアント情報も定義しないので、これらのメソッドをコールすると、SQLClientInfoException例外がスローされます。

- JDBC 4.0仕様では、java.sql.Arrayオブジェクトを作成するjava.sql.Connection.createArrayOfファクトリ・メソッドが定義されています。createArrayOfメソッドは配列要素型の名前を引数の1つに取ります。ここで、配列のタイプは匿名です。Oracleデータベースでは、匿名の配列型でなく、名前付きの配列型のみがサポートされます。このため、11.2のOracle JDBCドライバでは、createArrayOfメソッドはサポートされません。配列型を作成するには、Oracle固有のcreateARRAYメソッドを使用する必要があります。createArrayOfメソッドの詳細は、「ARRAYオブジェクトの作成」を参照してください。

- このドキュメントでは、これら新機能の概要のみを示します。これらの機能の詳細は、次の場所にあるJava 2 Platform, Standard Edition (JSE) 6.0の仕様を参照してください。

http://download.oracle.com/javase/6/docs/

Oracle Database 11gリリース2(11.2)のJDBCドライバでは、次のような機能を利用できます。

- ラッパー・パターンのサポート

- SQLXML型

- 機能拡張された例外階層とSQLException

- ROWIDデータ型

- LOBの作成

- 各国語キャラクタ・セットのサポート

ラッパー・パターンのサポート

ラッパー・パターンは、Javaアプリケーションで使用される一般的なコーディング・パターンで、データソース固有の従来のJDBC APIを超える機能を提供します。実際のリソースを表すプロキシ・クラス・インスタンスとしてラップされているリソースにアクセスする場合に、これらの拡張機能を使用する必要があることがあります。JDBC4.0では、リソース代理への直接アクセスを許可するために、プロキシによって表されるこれらのラップされたリソースにアクセスするための標準メカニズムを記述するWrapperインタフェースが導入されています。

Wrapperインタフェースでは、次の2つのメソッドが提供されています。

- public boolean isWrapperFor(Class<?> iface) throws SQLException;

- public <T> T unwrap(Class<T> iface) throws SQLException;

SQLデータを表すものを除く他のJDBC4.0インタフェースはすべてこのインタフェースを実装しています。これには、Connection、Statementとそのサブタイプ、ResultSetおよびメタデータ・インタフェースが含まれます。

関連項目:
http://download.oracle.com/javase/6/docs/api/java/sql/Wrapper.html

SQLXML型

JDBC 4.0標準で最も重要な更新内容の1つはSQL 2003標準で定義されたXMLデータ型のサポートです。現在、JDBCは、SQL/XMLデータベース・データ型 をサポートするためのマッピング・インタフェースを提供しています(java.sql.SQLXML)。この新しいJDBCインタフェースは、XMLの、Javaネイティブのバインディングを定義し、それにより、データベースXMLデータの処理をより簡単、より効率的にしています。

注意:

- また、SQLXML型のデータを使用するには、classpath環境変数にxdb.jarファイルとxmlparserv2.jarファイルを指定する必要があります(classpathにすでに指定されている場合を除く)。

- SQLXMLは、CachedRowsetオブジェクトではサポートされません。

java.sql.ConnectionインタフェースでcreateSQLXMLメソッドをコールすることによって、XMLのインスタンスを作成することができます。このメソッドは、空のXMLオブジェクトを戻します。

次に示すように、PreparedStatement、CallableStatementおよびResultSetインタフェースは拡張され、適切なgetterメソッドとsetterメソッドが用意されました。

- PreparedStatement: メソッドsetSQLXMLが追加されました。

- CallableStatement: メソッドgetSQLXMLおよびsetSQLXMLが追加されました。

- ResultSet: メソッドgetSQLXMLが追加されました。

oracle.jdbc.getObjectReturnsXMLTypeプロパティ

Oracle Database 10gと、Oracle Database 11gの初期バージョンでは、Oracle JDBCドライバは、Oracleの独自規格の拡張機能を介してOracle SQL XML型(XMLType)をサポートしていました。XML値はoracle.xdb.XMLTypeクラスのインスタンスによって表され、SQL XMLType値はJDBC標準のgetObject、setObjectおよびupdateObjectの各メソッドを介して読取りと、設定が行われていました。

JDBC標準では、SQL XML型の列でコールされた場合、java.sql.SQLXML型のインスタンスを戻すことを、getObjectメソッドに求めています。しかし、旧バージョンのOracle JDBCドライバでは、oracle.xdb.XMLTypeのインスタンスが戻されます。これは、JDBC標準に準拠していません。

Oracle JDBCドライバの現在のリリースでは新しい接続プロパティ( oracle.jdbc.getObjectReturnsXMLType)が導入され、JDBC標準に準拠しています。このプロパティをfalseに設定すると、getObjectメソッドはjava.sql.SQLXML型のインスタンスを戻します。そうするには、javacでプログラムをコンパイルする際に次のコマンドライン・オプションを使用します。

-Doracle.jdbc.getObjectReturnsXMLType="false"

oracle.xdb.XMLTypeを使用する既存のOracle独自規格のSQL XMLTypeサポートに依存している場合、次のコマンドライン・オプションを使用することにより、このプロパティの値をtrueに戻すことができます。

-Doracle.jdbc.getObjectReturnsXMLType="true"

oracle.jdbc.getObjectReturnsXMLTypeプロパティの値は、trueまたはfalseのブール値を表すStringです。このプロパティの値がtrueの場合、getObjectメソッドは、SQL XMLTypeの列に対してコールされるとoracle.xdb.XMLTypeインスタンスを戻します。これが、oracle.jdbc.getObjectReturnsXMLTypeプロパティのデフォルト値です。このプロパティの値がfalseの場合、getObjectメソッドはjava.sql.SQLXMLインスタンスを戻します。これは、標準のJDBC準拠モードです。

注意:
oracle.jdbc.getObjectReturnsXMLTypeプロパティは、getObjectメソッドの結果のみに影響を及ぼします。他のメソッドはすべて、プロパティの値に関係なく、標準のJDBC 4.0に準拠します。

例

例3-1 SQLXMLデータへのアクセス

次の例は、StringからXMLのインスタンスを作成し、データベースにXMLデータを書き込み、データベースからXMLデータを取得する方法を示しています。

import java.sql.*;
import java.util.Properties;
import oracle.jdbc.pool.OracleDataSource;

public class SQLXMLTest
{

public static void main(String[] args)
{

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
PreparedStatement ps = null;

String xml = "<?xml version=\"1.0\"?>\n" +
"<oldjoke>\n" +
"<burns>Say <quote>goodnight</quote>, Gracie.</burns>\n" +
"<allen><quote>Goodnight, Gracie.</quote></allen>\n" +
"<applause/>\n" +
"</oldjoke>";

try
{

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@//localhost:1521/orcl");
ods.setUser("scott");
ods.setPassword("tiger");
conn = ods.getConnection();

ps = conn.prepareStatement("insert into x values (?, ?)");
ps.setString(1, "string to string");
SQLXML x = conn.createSQLXML();
x.setString(xml);
ps.setSQLXML(2, x);
ps.execute();
x.free();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from x");
while (rs.next())
{

System.out.println(rs.getString(1) + "\n" + rs.getSQLXML(2).getString());
}

rs.close();
ps.close();
}

catch (SQLException e){e.printStackTrace ();}

}
}

注意:
空のXMLを指定してsetterメソッドをコールすると、SQLExceptionがスローされます。getterメソッドが空のXMLを戻すことはありません。

関連項目:
JSR 173: XML用のストリーミングAPI(次の場所を参照)
http://www.jcp.org/aboutJava/communityprocess/first/jsr173/

機能拡張された例外階層とSQLException

JDBC 3.0では、SQLExceptionという単一の例外しかサポートされていません。ただし、エラーはカテゴリが多いので、区別すると便利です。この機能では、様々なカテゴリのエラーを特定するために、SQLExceptionクラスのサブクラスがサポートされています。永続エラーと一時エラーの切分けが、主要な切分けになります。永続エラーは、システムの正しい動作の結果であり、常に発生します。一時エラーは、タイムアウトなど、システムの一部で障害が発生した結果であり、再発しない場合もあります。

JDBC 4.0では、一時エラー、永続エラーおよびそれらエラーの様々なカテゴリを表現するために、例外が追加されています。

また、SQLExceptionクラスとそのサブクラスは、J2SE関連の例外機能をサポートするために機能拡張されています。

ROWIDデータ型

JDBC 4.0では、SQLのROWID値を表現するために、java.sql.RowIdデータ型がサポートされています。ResultSetインタフェースおよびCallableStatementインタフェースで定義されているgetterメソッドを使用すると、RowId値を取り出すことができます。開発者は、パラメータ化されたPreparedStatementの中でRowId値を使用して、RowIdオブジェクトのパラメータを設定したり、更新可能な結果セットの中で使用して、列を特定のRowId値に更新したりできます。

RowIdオブジェクトは、指定された行が削除されるまで有効です。RowIdオブジェクトは、次の場合にも有効なことがあります。

- 作成元トランザクションの期間中。

- 作成元セッションの期間中。

- RowIdオブジェクトが永続的に有効である期間(未定義)。

DatabaseMetaData.getRowIdLifetimeメソッドをコールすると、RowIDオブジェクトの存続期間を確認できます。

LOBの作成

JDBC 4.0では、BLOB、CLOBおよびNCLOBオブジェクトの作成をサポートするために、Connectionインタフェースが機能拡張されています。このインタフェースでサポートされているcreateBlob、createClobおよびcreateNClobメソッドを使用すると、Blob、ClobおよびNClobオブジェクトを作成できます。

作成されたLOB(Large OBject)にデータは含まれません。java.sql.Blob、java.sql.Clobおよびjava.sql.NClobインタフェースで使用可能なAPIをコールして、これらのオブジェクトにデータを追加または取得できます。これらのオブジェクトからは、内容の全体または一部を取り出すことができます。次のコードでは、BLOBオブジェクトのオフセット200の位置から100バイトのデータを取り出す方法を示しています。

...
Connection con = DriverManager.getConnection(url, props);
Blob aBlob = con.createBlob();
// Add data to the BLOB object.
aBlob.setBytes(...);
...
// Retrieve part of the data from the BLOB object.
InputStream is = aBlob.getBinaryStream(200, 100);
...

setBlob、setClobおよびsetNClobメソッドを使用して、PreparedStatementオブジェクトにLOBを入力パラメータとして渡すこともできます。updateBlob、updateClobおよびupdateNClobメソッドを使用すると、更新可能結果セット内の列値を更新できます。

これらのLOBは一時LOBで、一時LOBを使用する必要がある場合に使用します。データベース内の記憶域を永続的にするには、これらのLOBを表に書き込む必要があります。

関連項目:
「一時LOBの使用」

一時LOBは、作成元のトランザクションの期間中は少なくとも有効です。ただし、トランザクションの実行期間が長いと、メモリーの使用が保証されない場合があります。次のようにLOBのfreeメソッドをコールすると、LOBを解放できます。

...
Clob aClob = con.createClob();
int numWritten = aClob.setString(1, val);
aClob.free();
...

各国語キャラクタ・セットのサポート

JDBC 4.0では、各国語キャラクタ・セットの型にアクセスするためのNCHAR、NVARCHAR、LONGNVARCHARおよびNCLOBというJDBC型が導入されています。これらの型は、各国語キャラクタ・セットを使用して値がエンコードされる点を除き、CHAR、VARCHAR、LONGVARCHARおよびCLOB型に類似しています。

4 Oracle拡張機能

Oracleには、Java Database Connectivity(JDBC)標準の実装を拡張するJavaクラスとインタフェースが用意されており、開発者は、Oracleデータ型にアクセスして操作し、Oracleパフォーマンス拡張機能を使用できます。この章では、JDBC標準実装を拡張するためにOracleで提供されるクラスとインタフェースの概要を示します。また、この拡張機能がサポートする主な機能についても説明します。

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

- Oracle拡張機能の概要

- Oracle拡張機能

- Oracle JDBCパッケージ

- Oracle文字データ型のサポート

- その他のOracle型拡張機能

- DML RETURNING

- PL/SQL索引付き表へのアクセス

注意:
この章では、主に型拡張機能について説明します。パフォーマンス拡張機能の詳細は、第23章「パフォーマンス拡張機能」で説明します。

Oracle拡張機能の概要

標準機能に加えて、Oracle JDBCドライバにはOracle固有型拡張機能およびパフォーマンス拡張機能があります。これらの拡張機能は、次のJavaパッケージに用意されています。

- oracle.sql
Oracle形式でSQLデータを示すクラスを提供します。

- oracle.jdbc
Oracle型形式でのデータベース・アクセスおよび更新をサポートするためのインタフェースを提供します。

関連項目:
「Oracle JDBCパッケージ」

Oracle拡張機能

JDBCへのOracle拡張機能には、Oracleデータベースを操作する能力を高めるいくつかの機能があります。それは次の機能です。

- JDBCを使用したデータベース管理

- Oracleデータ型のサポート

- Oracleオブジェクトのサポート

- スキーマの命名サポート

- DML RETURNING

- PL/SQL索引付き表へのアクセス

JDBCを使用したデータベース管理

Oracle Database 11gリリース1(11.1)で導入された新しいJDBCメソッドstartupおよびshutdown(oracle.jdbc.OracleConnectionインタフェース内)を使用すると、Oracle Databaseインスタンスの起動と停止を実行できます。Oracle Databaseのデータベース変更通知機能もサポートされています。これらの新機能については「データベース管理」で詳しく説明します。

Oracleデータ型のサポート

Oracle JDBC拡張機能の1つは、oracle.sqlパッケージの型のサポートです。このパッケージには、Oracle形式でのデータの正確な表現であるクラスが含まれています。プログラムでoracle.sql型を使用する際には、次の重要な点に注意してください。

- 数値型データの場合、標準Java型への変換では、データ変換プロセスの制限のために完全な精度が維持されません。データ損失の問題を最小限に抑えるには、BigDecimal型を使用してください。

- 特定のデータ型では、標準Java型への変換がシステムの設定によって決まる可能性があり、プログラムが予想どおりに実行されない場合があります。これは、oracle.sql型から標準Java型へのデータ変換中に発生することが知られている制限です。

- プログラムの機能が、1つの表からのデータの読取りと、もう1つの表への同じデータの書込みに限定されている場合、数値および日付データについては、標準Java型と比べてoracle.sql型の方がわずかに速くなります。しかし、比較や印刷などの単純なデータ操作が1つでも含まれている場合は、標準Java型の方が速くなります。

- oracle.sql.CHARはOracle形式に従うデータの正確な表現ではありません。oracle.sql.CHARはjava.lang.Stringから構成されます。java.lang.Stringの方が常に高速で、同じキャラクタ・セットを表すため、いくつかのサポートされていないキャラクタ・セットを除いて、oracle.sql.CHARを使用する利点がありません。

注意:
標準のJava型を使用して、既存のoracle.sql型のデータを標準のJava型に変換することを強くお薦めします。内部的には、Oracle JDBCドライバはJava標準型のパフォーマンスを最適化するように動作します。oracle.sql型は、下位互換性のためにのみサポートされており、使用は推奨されません。

関連項目:

- パッケージoracle.sql

- 「Oracle文字データ型のサポート」

- 「その他のOracle型拡張機能」

Oracleオブジェクトのサポート

Oracle JDBCはデータベース内の構造化オブジェクトの使用をサポートしています。ここで、オブジェクトのデータ型はネスト属性を持つユーザー定義の型です。たとえば、ユーザー・アプリケーションがEmployeeオブジェクト型を定義し、各Employeeオブジェクトが、firstname属性(文字列)、lastname属性(文字列)およびemployeenumber属性(整数値)を持つ例が考えられます。

Oracle JDBCは、Oracleオブジェクト・データ型をサポートします。JavaアプリケーションでOracleオブジェクト・データ型を使用する場合、次の点を考慮する必要があります。

- Oracleオブジェクト・データ型とJavaクラス間のマップ方法

- Oracleオブジェクトの属性を対応するJavaオブジェクトに格納する方法

- SQLとJava形式間で属性データを変換する方法

- データへのアクセス方法

Oracleオブジェクトは、弱い型指定のjava.sql.Struct、または強い型指定のカスタマイズされたクラスのいずれかにマップできます。これらの強い型指定はカスタムJavaクラスと呼ばれ、標準java.sql.SQLDataインタフェースまたはOracle拡張機能oracle.sql.ORADataインタフェースのいずれかを実装する必要があります。各インタフェースは、SQLとJavaとの間でデータ変換を行うメソッドを指定します。

注意:
CustomDatumインタフェースにかわってORADataインタフェースが導入されました。CustomDatumインタフェースはOracle Databaseリリース11.1以降はサポート対象外になりました。

Oracleオブジェクトに対応するカスタムJavaクラスを作成する場合は、Oracle JPublisherユーティリティを使用することをお薦めします。Oracle JPublisherは、この作業をコマンドライン・オプションでシームレスに実行し、SQLDataまたはORADataインタフェース実装のいずれかを生成できます。

SQLDataインタフェース実装の場合、型マップによって、Oracleオブジェクト・データ型とJavaクラス間の対応関係が定義されます。型マップは、各Oracleオブジェクト・データ型に対応するJavaクラスを指定するオブジェクトです。Oracle JDBCはこれらの型マップを使用して、結果セットからOracleオブジェクト・データを取り出す際に、どのJavaクラスのインスタンス化およびデータ移入を行うかを決定します。

注意:
移植性が重要ではない場合は、SQLDataインタフェースのかわりにORADataインタフェースを使用することをお薦めします。ORADataインタフェースは、Oracleプラットフォームが提供する、Javaを使用するその他の機能とともに、より容易にかつ柔軟に動作します。

JPublisherは、カスタムJavaクラスのgetXXXメソッドを自動的に定義します。このメソッドはデータをJavaアプリケーションに取り込みます。

関連項目:

- 第13章「Oracleオブジェクト型の操作」

- 『Oracle Database JPublisherユーザーズ・ガイド』

スキーマの命名サポート

Oracleオブジェクト・データ型クラスには、完全修飾スキーマ名の受入れおよび復帰を行う機能があります。完全修飾スキーマ名は、次の構文になります。

{[schema_name].}[sql_type_name]

ここで、schema_nameはスキーマの名前、sql_type_nameはオブジェクトのSQL型名で、schema_nameとsql_type_nameはピリオド(.)で区切られています。

JDBCでオブジェクト型を指定するには、その完全修飾名を使用します。型名が現行ネームスペース内、つまり現行スキーマ内にある場合は、スキーマ名を入力する必要はありません。スキーマは、次の規則に従って命名されます。

- スキーマ名と型名は、どちらも引用符で囲んでも囲まなくてもかまいません。ただし、CORPORATE.EMPLOYEEのように、SQL型名にピリオドが含まれている場合は、型名を引用符で囲む必要があります。

- JDBCドライバは、オブジェクト名内の引用符で囲まれていない最初のピリオドを検索して、ピリオドの前の文字列をスキーマ名として使用し、ピリオドの後の文字列を型名として使用します。ピリオドが見つからない場合、JDBCドライバは現行スキーマをデフォルトとします。つまり、オブジェクト型名が現行スキーマに属している場合は、完全修飾名を指定するかわりに、スキーマを指定せずに型名のみを指定できます。これが、型名にピリオドが含まれない場合に型名を引用符で囲む理由です。
たとえば、ユーザーScottがperson.addressという型を作成し、自分のセッション内でそれを使用するとします。Scottは、スキーマ名を省略して、person.addressで型をJDBCドライバに渡します。この場合、person.addressを引用符で囲まないとピリオドが検出され、JDBCドライバはpersonをスキーマ名、addressを型名として誤って解釈してしまいます。

- JDBCは、オブジェクト型名の文字列をデータベースにそのまま渡します。つまり、JDBCドライバは、オブジェクト型名が引用符で囲まれていてもその大/小文字を変更しません。
たとえば、Scott.PersonTypeがJDBCドライバにオブジェクト型名として渡されると、JDBCドライバはその文字列をそのままデータベースに渡します。別の例として、型名の文字列内に空白文字が含まれている場合、JDBCドライバは空白文字を削除しません。

DML RETURNING

Oracle Databaseでは、データ操作言語(DML)文にRETURNING句を使用できます。これによって、2つのSQL文を1文に結合できます。DML RTURNINGは、Oracle JDBC Oracle Call Interface(OCI)ドライバとOracle JDBC Thinドライバの両方でサポートされます。

関連項目:
「DML RETURNING」

PL/SQL索引付き表へのアクセス

Oracle JDBCドライバを使用すると、JDBCアプリケーションで、索引付き表パラメータを使用してPL/SQLをコールできます。Oracle JDBCドライバは、スカラー・データ型のPL/SQL索引付き表をサポートします。

注意:
PL/SQLレコードの索引付き表はサポートされません。

関連項目:
「PL/SQL索引付き表へのアクセス」

Oracle JDBCパッケージ

この項では、Oracle JDBC拡張機能をサポートする、次のJavaパッケージについて説明します。

- パッケージoracle.sql

- パッケージoracle.jdbc

注意:

- 可能な場合はJDBC標準型またはJava型の使用をお薦めします。

- Oracle JDBCドライバは、複数の接続によるJDBC型の共有をサポートしていません。

パッケージoracle.sql

oracle.sqlパッケージは、SQL形式でデータへの直接アクセスをサポートしています。このパッケージは、主に、SQLデータ型とそのサポート・クラスへのJavaマッピングを提供するクラスで構成されています。実質的に、このクラスはSQLデータのJavaコンテナとして機能します。

oracle.sql.*データ型の各クラスは、すべてのデータ型に共通する機能をカプセル化したスーパークラスのoracle.sql.Datumを拡張します。その中には、JDBC 2.0準拠のデータ型に対応したクラスもあります。これらのクラスは、oracle.sql.Datumクラスを拡張すると同時に、java.sqlパッケージの標準JDBC 2.0インタフェースを実装します。

LONGおよびLONG RAWのSQL型と、REF CURSOR型カテゴリには、oracle.sql.*クラスは含まれません。これらの型では、標準JDBC機能を使用してください。たとえば、LONGまたはLONG RAWデータを、標準JDBC結果セットおよびコール可能文メソッドgetBinaryStreamおよびgetCharacterStreamを使用して入力ストリームとして取り出します。REF CURSOR型にはgetCursorメソッドを使用します。

注意:
パッケージoracle.sql.*の方は主に下位互換性、またはOracleの少数の特定機能(OPAQUE、OraData、TIMESTAMPTZなど)のサポートのために用意されています。

oracle.sql.*データ型の一般的なサポート

各Oracleデータ型クラスは、特に次の機能をサポートします。

- SQLデータ用のJavaバイト配列であるデータ記憶域。

- SQLデータをバイト配列で戻すgetBytes()メソッド。

- JDBC仕様の定義に従って、データを対応するJavaクラスのオブジェクトに変換するtoJdbc()メソッド。
JDBCドライバは、BFILEなどの、JDBC仕様の一部ではないOracle固有のデータ型を変換しません。ドライバは、対応するoracle.sql.*形式でオブジェクトを戻します。

- SQLデータをJava型に変換するのに適切なxxxValueメソッド。たとえば、stringValue、intValue、booleanValue、dateValueおよびbigDecimalValueがあげられます。

- 補足的な変換メソッド。データをストリームとして取り出すラージ・オブジェクト(LOB)クラスのメソッド、およびオブジェクト参照を使用してオブジェクト・データの取出しや設定を行うREFクラスのメソッドなど、データ型の機能に適したgetXXXおよびsetXXX。

クラスoracle.sql.STRUCTの概要

oracle.sql.STRUCTクラスは、java.sql.StructインタフェースのOracle実装です。このクラスは値クラスです。構成後にクラスの内容を変更しないでください。このクラスは、すべてのoracle.sql.*データ型のクラスと同様に、oracle.sql.Datumクラスのサブクラスです。

JDK 1.5でSTRUCTオブジェクトを作成する場合、oracle.jdbc.OracleConnectionインタフェースのcreateStructメソッドを使用します。STRUCTオブジェクトを作成するためのこのファクトリ・メソッドのシグネチャは、次のとおりです。

Struct createStruct (String typeName, Object[] attributes) throws SQLException

JDK 1.6でSTRUCTオブジェクトを作成する場合、標準のjava.sql.createStructメソッドを使用できます。

oracle.sql.STRUCTを使用するのではなく、JDBC標準型、java.sql.StructおよびJDBC標準メソッドを使用する必要があります。コードを移植可能にする場合、Oracle JDBCドライバのみがoracle.sql.STRUCT型のインスタンスを使用するので、標準型を使用する必要があります。

注意:
可能なかぎり、コードではJDBC標準機能の使用を強くお薦めします。

関連項目:
Oracle Database JDBC Java APIリファレンス

クラスoracle.sql.REFの概要

oracle.sql.REFクラスは、Oracleオブジェクト参照をサポートする一般クラスです。このクラスは、すべてのoracle.sql.*データ型のクラスと同様に、oracle.sql.Datumクラスのサブクラスです。

REFクラスには、オブジェクト参照を取り出して渡すためのメソッドがあります。ただし、オブジェクト参照の選択によって取り出されるのは、オブジェクトへのポインタのみです。これによってオブジェクト自体がインスタンス化されることはありません。ただし、REFクラスにはオブジェクト・データを取り出して渡すためのメソッドも含まれています。JDBCアプリケーションではREFオブジェクトを作成できません。データベースから取り出すことができるのは、既存のREFオブジェクトのみです。

oracle.sql.REFを使用するのではなく、JDBC標準型、java.sql.RefおよびJDBC標準メソッドを使用する必要があります。コードを移植可能にする場合、Oracle JDBCドライバのみがoracle.sql.REF型のインスタンスを使用するので、標準型を使用する必要があります。

注意:

可能なかぎり、コードではJDBC標準機能の使用を強くお薦めします。

関連項目:
Oracle Database JDBC Java APIリファレンス

クラスoracle.sql.ARRAYの概要

oracle.sql.ARRAYクラスは、Oracleコレクション、つまりVARRAYまたはNESTED TABLEのいずれかをサポートします。データベースからVARRAYまたはNESTED TABLEを選択すると、JDBCドライバは、その内容をARRAYクラスのオブジェクトとしてインスタンス化します。データの構造は、いずれの場合も同じです。oracle.sql.ARRAYクラスは、oracle.sql.Datumを拡張して、標準JDBC 2.0 java.sql.Arrayインタフェースを実装します。

注意:
oracle.sql.ARRAYを使用するのではなく、JDBC標準型、java.sql.ArrayおよびJDBC標準メソッドを使用する必要があります。コードを移植可能にする場合、Oracle JDBCドライバのみがoracle.sql.ARRAY型のインスタンスを使用するので、標準型を使用する必要があります。
可能なかぎり、コードではJDBC標準機能の使用を強くお薦めします。

OraclePreparedStatementインタフェースまたはOracleCallableStatementインタフェースのsetARRAYメソッドを使用すると、ARRAYをプリコンパイルされたSQL文への入力パラメータとして渡すことができます。同様に、OracleConnectionインタフェースのcreateARRAYメソッドを使用してARRAYオブジェクトを作成し、プリコンパイルされたSQL文またはコール可能文に渡し、データベースへの挿入などの操作を行う場合も考えられます。

関連項目:
「コレクション機能の概要」

クラスoracle.sql.BLOB、oracle.sql.CLOB、oracle.sql.BFILEの概要

バイナリ・ラージ・オブジェクト(BLOB)、キャラクタ・ラージ・オブジェクト(CLOB)およびバイナリ・ファイル(BFILE)は、大きすぎてデータベース表に直接格納できないデータ項目に使用します。一方、データベース表はデータの実際の場所を指すロケータを格納します。

注意:

- oracle.sql.BLOBクラスとoracle.sql.CLOBクラスは、それぞれ標準JDBC型であるjava.sql.Blobとjava.sql.Clobを実装します。Oracle拡張機能を使用するのではなく、JDBC標準型およびJDBC標準メソッドを使用する必要があります。コードを移植可能にする場合、Oracle JDBCドライバのみがOracle拡張機能のインスタンスを使用するので、標準型を使用する必要があります。
可能なかぎりJDBC標準機能の使用を強くお薦めします。

- oracle.sql.BFILEはOracle独自の拡張機能であり、これに相当するJDBC標準機能はありません。

oracle.sqlパッケージは、これらのデータ型を次のいくつかの方法でサポートします。

- BLOBは、ラージ非構造化バイナリ・データ項目を指し、oracle.sql.BLOBクラスによりサポートされます。

- CLOBは、ラージ文字データ項目を指し、oracle.sql.CLOBクラスによりサポートされます。

- BFILEは、外部ファイル(オペレーティング・システム・ファイル)の内容を指し、oracle.sql.BFILEクラスによりサポートされます。BFILEは読取り専用です。

BLOB、CLOBまたはBFILEの各ロケータは、標準的なSELECT文を使用してデータベースから選択できます。ただし、受け取るのはデータではなく、ロケータのみです。データの取出しには、追加処理が必要です。

関連項目:
第14章「LOBとBFILEの操作」

クラスoracle.sql.DATE、oracle.sql.NUMBERおよびoracle.sql.RAWの概要

これらのクラスは、プリミティブSQLデータ型を、Oracleネイティブの表現で保持します。ほとんどの場合、ドライバはこれらの型を内部的に使用しません。なるべく標準JDBC型を使用してください。

JavaのDoubleおよびFloat NaN値には等価のOracle NUMBER表現が存在しないため、Double.NaN値またはFloat.NaN値がoracle.sql.NUMBERクラスを使用してOracle NUMBERに変換されると、NullPointerExceptionが発生します。たとえば、次のコードにより、NullPointerExceptionが発生します。

oracle.sql.NUMBER n = new oracle.sql.NUMBER(Double.NaN);
System.out.println(n.doubleValue());  // throws NullPointerException

クラスoracle.sql.TIMESTAMP、oracle.sql.TIMESTAMPTZおよびoracle.sql.TIMESTAMPLTZの概要

JDBCドライバでは、次のような日付/時刻データ型をサポートしています。

- TIMESTAMP(TIMESTAMP)

- TIMESTAMP WITH TIME ZONE(TIMESTAMPTZ)

- TIMESTAMP WITH LOCAL TIME ZONE(TIMESTAMPLTZ)

JDBCドライバでは、DATEと日付/時刻データ型の間での変換が可能です。たとえば、DATE値としてTIMESTAMP WITH TIME ZONE列にアクセスできます。

JDBCドライバは、業界で最も一般的なタイムゾーン名と、JDKで定義されたタイムゾーン名をサポートしています。タイムゾーンは、java.util.TimeZoneクラスを使用して指定します。

注意:

- タイムゾーン・オブジェクトの作成にはTimeZone.getTimeZoneを使用しないでください。これは、Oracleのタイムゾーン・データ型では、JDKよりも多くのタイムゾーン名をサポートしているためです。

- 結果セットのTIMESTAMPLTZ列の後にLONG列が続く場合、LONG列を読み取ろうとするとエラーになります。

次のコードは、JDKに定義されていないタイムゾーン名であるUS_PACIFICにTimeZoneオブジェクトとCalendarオブジェクトを作成する方法を示します。

TimeZone tz = TimeZone.getDefault();
tz.setID("US_PACIFIC");
GregorianCalendar gcal = new GregorianCalendar(tz);

次のJavaクラスは、SQL日付/時刻データ型を表します。

- oracle.sql.TIMESTAMP

- oracle.sql.TIMESTAMPLTZ

- oracle.sql.TIMESTAMPLTZ

TIMESTAMP WITH LOCAL TIME ZONEデータにアクセスする前に、OracleConnection.setSessionTimeZone(String regionName)メソッドをコールして、セッション・タイム・ゾーンを設定します。このメソッドがコールされると、JDBCドライバは接続のセッション・タイム・ゾーンを設定、保存して、JDBCを介してアクセスされるTIMESTAMP WITH LOCAL TIME ZONEデータをセッション・タイム・ゾーンを使用して調整できるようにします。

注意:
TIMESTAMP WITH TIME ZONE型とTIMESTAMP WITH LOCAL TIME ZONE型は、標準のjava.sql.Timestamp型として表せます。TIMESTAMP WITH TIME ZONE型とTIMESTAMP WITH LOCAL TIME ZONE型のjava.sql.Timestampに対するバイト表現は簡単です。これは、TIMESTAMP WITH TIME ZONEデータ型とTIMESTAMP WITH LOCAL TIME ZONEデータ型の内部形式はGMTで、java.sql.Timestamp型オブジェクトは内部では、エポックからのミリ秒数であるミリ秒時間値を使用するためです。ただし、これらのデータ型のString表現には、サーバーから動的に取得され、クライアント側にキャッシュされているタイム・ゾーン情報が必要です。
JDBCドライバの旧バージョンでは、タイム・ゾーンのキャッシュは様々な接続で共有されていました。このため、様々なタイム・ゾーンでの非互換性が原因で問題が発生することがよくありました。Oracle Database 11.2リリースのJDBCドライバから、タイム・ゾーン・キャッシュは、データベースが提供するタイム・ゾーンのバージョンを基礎とします。この新設計のキャッシュは、タイム・ゾーンのバージョン非互換性に関連するどのような問題も回避します。

クラスoracle.sql.OPAQUEの概要

oracle.sql.OPAQUEクラスは、OPAQUE型の名前と特性および任意の属性を提供します。OPAQUE型では、インスタンスの連続バイトにのみアクセスできます。

注意:
OPAQUE型のサポートは限定されています。

パッケージoracle.jdbc

oracle.jdbcパッケージのインタフェースは、java.sqlのインタフェースに対するOracle拡張機能を定義します。これらの拡張機能は、Oracle SQL形式データおよびOracle固有の他の機能(Oracleパフォーマンス拡張機能など)にアクセスできます。

関連項目:
「oracle.jdbcパッケージ」

Oracle文字データ型のサポート

Oracle文字データ型には、SQL CHARおよびNCHARデータ型が含まれます。次の各項では、oracle.sql.*クラスを使用してこれらのデータ型にアクセスする方法について説明します。

- SQL CHARデータ型

- SQL NCHARデータ型

- クラスoracle.sql.CHAR

SQL CHARデータ型

SQL CHARデータ型には、CHAR、VARCHAR2およびCLOBデータ型が含まれます。これらのデータ型を使用すると、文字データをデータベース・キャラクタ・セットのコード体系で格納できます。データベースのキャラクタ・セットは、データベースの作成時に決まります。

SQL NCHARデータ型

SQL NCHARデータ型は、グローバリゼーション・サポート用に作成されたものです。SQL NCHARデータ型には、NCHAR、NVARCHAR2およびNCLOBデータ型が含まれます。これらのデータ型を使用すると、UnicodeデータをデータベースNCHARキャラクタ・セットのコード体系で格納できます。NCHARキャラクタ・セットは、データベースの作成時に決まり、変更されることはありません。

注意:
UnicodeStreamクラスが非推奨となってCharacterStreamクラスが導入されたため、NCHARデータ型でのアクセスではsetUnicodeStreamメソッドとgetUnicodeStreamメソッドはサポートされません。ストリーム・アクセスを使用する場合、setCharacterStreamメソッドとgetCharacterStreamメソッドを使用します。

SQL NCHARデータ型の使用方法は、SQL CHARデータ型の場合に類似しています。JDBCでは、対応するSQL CHARデータ型で使用されるのと同じクラスおよびメソッドを使用して、SQL NCHARデータ型にアクセスします。したがって、oracle.sqlパッケージには、SQL NCHARデータ型用の対応する別のクラスが定義されていません。同様に、SQL NCHARデータ型用のoracle.jdbc.OracleTypesクラスにも、対応する別の定数は定義されていません。

注意:
JDK 1.5の場合、JDBCプログラムは、特に各国語文字を必要とするこれらの列のためにsetFormOfUseメソッドをコールする必要があります。

次のコードは、SQL NCHARデータにアクセスする方法を示します。

//
// Table TEST has the following columns:
// - NUMBER
// - NVARCHAR2
// - NCHAR
//
oracle.jdbc.OraclePreparedStatement pstmt =
(oracle.jdbc.OraclePreparedStatement)
conn.prepareStatement("insert into TEST values(?, ?, ?)");

//
// oracle.jdbc.OraclePreparedStatement.FORM_NCHAR should be used for all NCHAR,
// NVARCHAR2 and NCLOB data types.
//

pstmt.setInt(1, 1);                    // NUMBER column
pstmt.setNString(2, myUnicodeString1);  // NVARCHAR2 column
pstmt.setNString(3, myUnicodeString2);  // NCHAR column
pstmt.execute();

クラスoracle.sql.CHAR

oracle.sql.CHARクラスは、文字データを処理および変換するためにOracle JDBCによって使用されます。このクラスは、文字データを変換するためのグローバリゼーション・サポート機能を提供します。このクラスには、グローバリゼーション・サポート・キャラクタ・セットおよび文字データという2つの主要な属性があります。グローバリゼーション・サポート・キャラクタ・セットは、文字データのエンコーディングを定義します。これは、CHARオブジェクトの作成時に必ず渡されるパラメータです。グローバリゼーション・サポート・キャラクタ・セット情報がない状態では、CHARオブジェクト内のデータ・バイトは無意味です。oracle.sql.CHARクラスは、SQL CHARおよびSQL NCHARの両方のデータ型に使用されます。

注意:
10g リリース1(10.1)より前のバージョンのOracle JDBCドライバでは、oracle.SQL.CHARを使用することでパフォーマンス上の利点がありました。Oracle Database 10g以上では、このような利点はありません。実際には、java.lang.Stringを使用することで最適なパフォーマンスを実現できます。すべてのOracle JDBCドライバが、Java UCS2キャラクタ・セット内のすべての文字データを処理します。oracle.sql.CHARを使用すると、データベース・キャラクタ・セットとUCS2キャラクタ・セットとの間の変換が発生します。

oracle.sql.CHARクラスに残された唯一の使用方法は、文字データをOracleグローバリゼーション・サポート・キャラクタ・セットでエンコードされたRAWバイトの形式で処理する場合です。Oracle Databaseから取り出された文字データはすべてjava.lang.Stringクラスを使用してアクセスしてください。別のソースからのバイト・データを処理する場合は、oracle.sql.CHARを使用してバイトをjava.lang.Stringに変換できます。

oracle.sql.CHARを変換するには、データ・バイトと、そのデータ・バイトのエンコードに使用するグローバリゼーション・サポート・キャラクタ・セットを示すoracle.sql.CharacterSetインスタンスを用意する必要があります。

Oracleオブジェクト属性であるCHARオブジェクトは、データベース・キャラクタ・セットで戻されます。

CHARオブジェクトは、必要に応じてJDBCドライバで自動的に作成されるため、まれに作成する必要がある場合でも、JDBCアプリケーション・コードでCHARオブジェクトを直接作成する必要はほとんどありません。

CHARオブジェクトを作成する場合は、CharacterSetクラスのインスタンスによって、CHARオブジェクトにキャラクタ・セット情報を提供する必要があります。このクラスの各インスタンスは、Oracleがサポートしているグローバリゼーション・サポート・キャラクタ・セットの1つを表します。CharacterSetインスタンスは、キャラクタ・セットのメソッドおよび属性をカプセル化し、主に他のキャラクタ・セットとの相互変換機能を提供します。

oracle.sql.CHARオブジェクトの作成

CHARオブジェクトを構築する際、次の一般的な手順に従ってください。

1. CharacterSetオブジェクトは、static CharacterSet.makeメソッドをコールして作成します。
このメソッドは、キャラクタ・セット・インスタンスのファクトリです。makeメソッドは、Oracleがサポートするキャラクタ・セットIDに対応する整数を入力として取ります。たとえば、次のようになります。

int oracleId = CharacterSet.JA16SJIS_CHARSET; // this is character set ID,
// 832
...
CharacterSet mycharset = CharacterSet.make(oracleId);

Oracleがサポートする各キャラクタ・セットは、事前定義済の一意なOracle IDを保持します。

2. CHARオブジェクトを作成します。
文字列または文字列を表すバイトを、キャラクタ・セットに基づくバイトの解釈方法を指定するCharacterSetオブジェクトとともに、コンストラクタに渡します。たとえば、次のようになります。

String mystring = "teststring";
...
CHAR mychar = new CHAR(teststring, mycharset);

CHARには、CharacterSetオブジェクトとともに、String、byte配列またはオブジェクトを入力として使用できる複数のコンストラクタがあります。Stringの場合、文字列は、CharacterSetオブジェクトが示すキャラクタ・セットに変換されてから、CHARオブジェクトに格納されます。

注意:

- CharacterSetオブジェクトをNULL値にすることはできません。

- CharacterSetクラスは抽象クラスであるため、コンストラクタを持ちません。インスタンスを作成するには、makeメソッドを使用するのが唯一の方法です。

- サーバーは、特別な値であるCharacterSet.DEFAULT_CHARSETをデータベース・キャラクタ・セットとして認識します。クライアントの場合、この値は無意味です。

- ユーザーがCharacterSetクラスを拡張することを、オラクル社は意図しておらず、お薦めもしません。

oracle.sql.CHAR Conversionメソッド

CHARクラスは、文字データを文字列に変換するための次のようなメソッドを提供します。

- getString
このメソッドは、CHARオブジェクトによって表された文字のシーケンスを文字列に変換し、Java Stringオブジェクトを戻します。無効なOracleIDを入力した場合、キャラクタ・セットは認識されず、getStringメソッドはSQLException例外をスローします。

- toString
このメソッドはgetStringメソッドと同じです。ただし、無効なOracleIDを入力すると、キャラクタ・セットが認識されず、toStringメソッドによりCHARデータの16進表現が戻されます。SQLException例外はスローされません。

- getStringWithReplacement
このメソッドはgetStringメソッドと同一ですが、CHARオブジェクトのキャラクタ・セットにUnicode表現のない文字が、デフォルトの置換文字で置き換えられる点が異なります。デフォルトの置換文字はキャラクタ・セットによって異なりますが、多くの場合は疑問符(?)です。

データベース・サーバーとクライアント、またはクライアント上で動作するアプリケーションでは、異なるキャラクタ・セットを使用できます。CHARクラスのメソッドを使用してデータをサーバーとクライアント間で転送する場合、JDBCドライバはデータをサーバーのキャラクタ・セットからクライアントのキャラクタ・セットに(またはその逆に)変換する必要があります。データを変換する際、ドライバはグローバリゼーション・サポートを使用します。

関連項目:
第19章「グローバリゼーション・サポート」

その他のOracle型拡張機能

Oracle JDBCドライバは、Oracle固有のBFILEデータ型、ROWIDデータ型およびREF CURSOR型をサポートしますが、これらは標準JDBC仕様に含まれていません。このセクションでは、ROWIDおよびREF CURSOR型の拡張について説明します。ROWIDはJava文字列としてサポートされ、REF CURSOR型はJDBC結果セットとしてサポートされます。

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

- Oracle ROWID型

- Oracle REF CURSOR型カテゴリ

- Oracle BINARY_FLOAT型およびBINARY_DOUBLE型

- Oracle SYS.ANYTYPE型およびSYS.ANYDATA型

- oracle.jdbcパッケージ

Oracle ROWID型

ROWIDは、Oracle Database表の行ごとに一意の識別タグです。ROWIDは、各行のIDを含む仮想列とみなすこともできます。

oracle.sql.ROWIDクラスは、ROWID SQLデータ型のコンテナとして提供されます。

ROWIDは、java.sql.ResultSetインタフェースで指定されるgetCursorNameメソッドおよびjava.sql.Statementインタフェースで指定されるsetCursorNameメソッドに類似した機能を提供します。

問合せにROWID擬似列を指定した場合は、結果セットgetStringメソッドを使用してROWIDを取得できます。また、setStringメソッドを使用すると、ROWIDにPreparedStatementパラメータをバインドできます。これによって、次の例に示すように、埋込み更新を実行できます。

注意:
oracle.sql.ROWIDクラスを使用するのは、J2SE 1.5を使用する場合のみとしてください。JSE 6の場合は、標準のjava.sql.RowIdインタフェースを使用してください。

例

次の例では、ROWIDデータに対するアクセスおよび操作の方法を示します。

注意:
次の例は、JSE 6でのみ動作します。

Statement stmt = conn.createStatement();

// Query the employee names with "FOR UPDATE" to lock the rows.
// Select the ROWID to identify the rows to be updated.

ResultSet rset =
stmt.executeQuery ("SELECT ename, rowid FROM emp FOR UPDATE");

// Prepare a statement to update the ENAME column at a given ROWID

PreparedStatement pstmt =
conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");

// Loop through the results of the query
while (rset.next ())
{
String ename = rset.getString (1);
RowId rowid = rset.getROWID(2); // Get the ROWID as a String
pstmt.setString (1, ename.toLowerCase ());
pstmt.setROWID (2, rowid); // Pass ROWID to the update statement
pstmt.executeUpdate ();     // Do the update
}

Oracle REF CURSOR型カテゴリ

カーソル変数は、問合せ作業領域の(内容でなく)メモリーの場所を保持します。カーソル変数を宣言すると、ポインタが作成されます。SQLでは、ポインタはデータ型REF xを取ります。ここで、REFはREFERENCEの省略形で、xは参照されるエンティティを表します。したがって、REF CURSORはカーソル変数への参照を表します。多くの作業領域を参照する多くのカーソル変数が存在する可能性があるため、REF CURSORは、異なる多くの型のカーソル変数を識別するカテゴリまたはデータ型指定子と考えることができます。

注意:
REF CURSORインスタンスはスクロール可能ではありません。

カーソル変数を作成するには、まずREF CURSORカテゴリに属する型を識別します。たとえば、次のようになります。

DECLARE TYPE DeptCursorTyp IS REF CURSOR

次に、カーソル変数をDeptCursorTyp型と宣言することによって、カーソル変数を作成します。

dept_cv DeptCursorTyp  - - declare cursor variable
...

REF CURSORは、特定のデータ型ではなく、データ型のカテゴリです。

ストアド・プロシージャにより、REF CURSORカテゴリのカーソル変数が戻されます。この出力は、データベース・カーソルまたはJDBC結果セットと等価です。REF CURSORには、基本的に問合せの結果が格納されます。

JDBCでは、REF CURSORは、ResultSetオブジェクトとしてインスタンス化され、次の方法でアクセスできます。

1. ストアド・プロシージャをコールするにはJDBCコール可能文を使用します。出力パラメータがあるため、プリコンパイルされたSQL文ではなく、コール可能文を使用する必要があります。

2. ストアド・プロシージャによってREF CURSORが戻されます。

3. Javaアプリケーションによってコール可能文がOracleコール可能文にキャストされ、OracleCallableStatementクラスのgetCursorメソッドを使用してREF CURSORがJDBC ResultSetオブジェクトとしてインスタンス化されます。

4. 結果セットは要求どおりに処理されます。

重要:
REF CURSORと関連付けられたカーソルは、そのREF CURSORを作成したStatementオブジェクトがクローズされるたびにクローズされます。
過去のリリースとは異なり、REF CURSORのインスタンス化が行われた結果セット・オブジェクトがクローズされても、REF CURSORに関連付けられたカーソルはクローズされません。

例

この例では、REF CURSORデータにアクセスする方法を示します。

import oracle.jdbc.*;
...
CallableStatement cstmt;
ResultSet cursor;

// Use a PL/SQL block to open the cursor
cstmt = conn.prepareCall
("begin open ? for select ename from emp; end;");

cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
cursor = ((OracleCallableStatement)cstmt).getCursor(1);

// Use the cursor like a standard ResultSet
while (cursor.next ())
{System.out.println (cursor.getString(1));}

この例について、説明します。

- CallableStatementオブジェクトは、接続クラスのprepareCallメソッドを使用して作成されます。

- コール可能文によって、REF CURSORを戻すPL/SQLプロシージャが実装されます。

- コール可能文の出力パラメータは、通常どおり登録してその型を定義する必要があります。REF CURSORには、型コードOracleTypes.CURSORを使用します。

- コール可能文が実行され、REF CURSORが戻されます。

- 標準JDBC APIのOracle拡張機能getCursorメソッドを使用するため、CallableStatementオブジェクトをOracleCallableStatementにキャストします。REF CURSORがResultSetオブジェクトに戻されます。

Oracle BINARY_FLOAT型およびBINARY_DOUBLE型

Oracle BINARY_FLOAT型およびBINARY_DOUBLE型は、IEEE 574のfloat型とdouble型のデータを格納するために使用します。これらの型は、負とゼロおよびNaNを除いて、Javaのfloatスカラー型とdoubleスカラー型に相当します。

関連項目:
Oracle Database SQL言語リファレンス

BINARY_DOUBLE列を問合せに含めると、データはデータベースからバイナリ形式で取り出されます。getDoubleメソッドも、データをバイナリ形式で戻します。一方、NUMBERデータ型の列の場合は、数値ビットが戻り、Javaのdoubleデータ型に変換されます。

注意:
SQL FLOAT型、DOUBLE PRECISION型およびREALデータ型のOracle表現は、Oracle NUMBER表現を使用します。BINARY_FLOAT型とBINARY_DOUBLEデータ型は、独自の型とみなされます。

PreparedStatementインタフェースのJDBC標準setDouble(int, double)メソッドのコールは、Javaのdouble引数をOracleのNUMBERスタイル・ビットに変換してからデータベースに送信します。一方、oracle.jdbc.OraclePreparedStatementインタフェースのsetBinaryDouble(int, double)メソッドは、データを内部バイナリ・ビットに変換してからデータベースに送信します。

使用するデータ形式が、PreparedStatementインタフェースのターゲット・パラメータの型と一致していることを確認してください。この確認によって、データの正確性が保持され、CPUの使用も最小限に抑えられます。NUMBERパラメータにsetBinaryDoubleを使用すると、バイナリ・ビットはサーバーに送信され、NUMBER形式に変換されます。データの正確性は保持されますが、サーバーのCPU負荷は増加します。BINARY_DOUBLEパラメータにsetDoubleを使用すると、データは、クライアントでNUMBERビットに変換されてからサーバーに送信され、そこでバイナリ形式に再変換されます。この方法では、クライアントとサーバーの両方でCPU負荷が増大し、データの精度も低下する可能性があります。

SetFloatAndDoubleUseBinary接続プロパティがtrueに設定されていると、JDBC標準API、setFloat(int, float)、setDouble(int, double)、およびすべての変数では、NUBMERビットではなく、内部バイナリ・ビットを送信するようになります。

注意:
ここでは、主にBINARY_DOUBLEについて説明しましたが、BINARY_FLOATについても同じ内容が適用されます。

Oracle SYS.ANYTYPE型およびSYS.ANYDATA型

Oracle Database 11gリリース2(11.2)では、SYS.ANYTYPEおよびSYS.ANYDATAというOracle型にアクセスするためのJavaインタフェースがサポートされています。

関連項目:
これらのOracle型の詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

SYS.ANYTPE型のインスタンスには、オブジェクト型およびコレクション型も含め、SQL型の型記述(永続か一時、名前付きか名前なし)が含まれます。oracle.sql.TypeDescriptorクラスを使用すると、SYS.ANYTYPE型にアクセスできます。ANYTYPEインスタンスは、PL/SQLのプロシージャまたはSQLのSELECT文(SYS.ANYTYPEを列型として使用)を使用して取り出すことができます。ANYTYPEインスタンスをデータベースから取り出すには、getObjectメソッドを使用します。このメソッドは、TypeDescriptorのインスタンスを戻します。

次の任意のANYTYPEインスタンスを取り出すことができます。

- 一時オブジェクト型

- 一時事前定義済型

- 永続オブジェクト型

- 永続事前定義済型

例4-1 SYS.ANYTYPE型へのアクセス

次のコードは、ANYTYPEのインスタンスをデータベースから取り出す方法を示しています。

...
ResultSet rs = stmt.executeQuery("select anytype_column from my_table");
TypeDescriptor td = (TypeDescriptor)rs.getObject(1);
short typeCode = td.getInternalTypeCode();
if(typeCode == TypeDescriptor.TYPECODE_OBJECT)
{
// check if it's a transient type
if(td.isTransientType())
{
AttributeDescriptor[] attributes = ((StructDescriptor)td).getAttributesDescriptor();
for(int i=0; i<attributes.length; i++)
System.out.println(attributes[i].getAttributeName());
}
else
{    System.out.println(td.getTypeName());  }}
...

例4-2 一時オブジェクト型のPL/SQLによる作成とJDBCによる取出し

次のサンプル・コードは、JDBCによる一時オブジェクト型の取出し方法を示しています。

...
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall
("BEGIN ? := transient_obj_type (); END;");
cstmt.registerOutParameter(1,OracleTypes.OPAQUE,"SYS.ANYTYPE");
cstmt.execute();
TypeDescriptor obj = (TypeDescriptor)cstmt.getObject(1);
if(!obj.isTransient())
System.out.println("This must be a JDBC bug");
cstmt.close();
return obj;
...

例4-3 ANYTYPEをINパラメータとして受け取るPL/SQLストアド・プロシージャのコール

次のコードは、ANYTYPEをINパラメータとして受け取るPL/SQLストアド・プロシージャのコール方法を示しています。

...
CallableStatement cstmt = conn.prepareCall("BEGIN ? := dumpanytype(?); END;");
cstmt.registerOutParameter(1,OracleTypes.VARCHAR);
// obj is the instance of TypeDescriptor that you have retrieved
cstmt.setObject(2,obj);
cstmt.execute();
String str = (String)cstmt.getObject(1);
...

oracle.sql.ANYDATAクラスを使用すると、データベースからSYS.ANYDATAインスタンスにアクセスできます。このクラスのインスタンスは、oracle.sql.Datumの任意の有効なインスタンスから取得できます。convertDatumファクトリ・メソッドは、Datumのインスタンスを受け取り、ANYDATAのインスタンスを戻します。このファクトリ・メソッドの構文は、次のとおりです。

public static ANYDATA convertDatum(Datum datum) throws SQLException

oracle.sql.ANYDATAのインスタンスを作成するためのサンプル・コードを、次に示します。

// struct is a valid instance of oracle.sql.STRUCT that either comes from the
// database or has been constructed in Java.
ANYDATA myAnyData = ANYDATA.convertDatum(struct);

例4-4 ANYDATAのインスタンスに対するデータベースからのアクセス

...
// anydata_table has been created as:
// CREATE TABLE anydata_tab (data SYS.ANYDATA)
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select data from my_anydata_tab");
while(rs.next())
{
ANYDATA anydata = (ANYDATA)rs.getObject(1);
if(!anydata.isNull())
{
TypeDescriptor td = anydata.getTypeDescriptor();
if(td.getTypeCode() == OracleType.TYPECODE_OBJECT)
STRUCT struct = (STRUCT)anydata.accessDatum();
}
}
...

例4-5 データベース表へのANYDATAとしてのオブジェクトの挿入

表およびオブジェクト型が次のように定義されているものとします。

CREATE TABLE anydata_tab ( id NUMBER, data SYS.ANYDATA)

CREATE OR REPLACE TYPE employee AS OBJECT ( empno NUMBER, ename VARCHAR2(10) )

SQLオブジェクト型EMPLOYEEのインスタンスを作成し、それをanydata_tabに挿入するには、次のようなコードを記述します。

...
PreparedStatement pstmt = conn.prepareStatement("insert into anydata_table values (?,?)");
StructDescriptor sd = StructDescriptor.createDescriptor("EMPLOYEE",(OracleConnection)conn);
Object[] objattr = new Object[2];
objattr[0] = new BigDecimal(1120);
objattr[1] = new String("Papageno");
STRUCT myEmployeeStr = new STRUCT(sd,conn,objattr);
ANYDATA anyda = ANYDATA.convertDatum(myEmployeeStr);
pstmt.setInt(1,123);
pstmt.setObject(2,anyda);
pstmt.executeUpdate();
...

例4-6 データベース表からのANYDATA列の選択

...
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select data from anydata_table");
while(rs.next())
{
ANYDATA obj = (ANYDATA)rs.getObject(1);
TypeDescriptor td = obj.getTypeDescriptor();
}
rs.close();
stmt.close();
...

oracle.jdbcパッケージ

oracle.jdbcパッケージのインタフェースは、java.sqlのインタフェースに対するOracle拡張機能を定義します。これらの拡張機能によって、この章に記載されているSQL形式のデータへのアクセスが可能になります。また、Oracleパフォーマンス拡張要素など、Oracle固有の他の機能へのアクセスも可能になります。

表4-1に、oracle.jdbcパッケージに含まれる接続に使用する主なインタフェースとクラス、文および結果セットのリストを示します。

表4-1 oracle.jdbcパッケージの主なインタフェースおよびクラス

名前

インタフェースまたはクラス

主要機能

OracleDriver

クラス

java.sql.Driverを実装します。

OracleConnection

インタフェース

Oracle Databaseインスタンスを起動または停止するためのメソッド、Oracle Statementオブジェクトを戻すメソッド、および現行接続で実行される任意の文に対応したOracleパフォーマンス拡張機能を設定するメソッドを提供します。

java.sql.Connectionを実装します。

OracleStatement

インタフェース

文ごとにOracleパフォーマンス拡張機能を設定するメソッドを提供します。

OraclePreparedStatementおよびOracleCallableStatementのスーパータイプです。

java.sql.Statementを実装します。

OraclePreparedStatement

インタフェース

oracle.sql.*型をプリコンパイルされたSQL文にバインドするsetXXXメソッドを提供します。

SELECT文を実行しないでプリコンパイルされたSQL文からメタデータを取得するgetMetaDataメソッドを提供します。

java.sql.PreparedStatementを実装します。

OracleStatementを機能拡張します。

OracleCallableStatementのスーパータイプです。

OracleCallableStatement

インタフェース

データをoracle.sql形式で取り出すgetXXXメソッド、およびoracle.sql.*型をコール可能文にバインドするsetXXXメソッドを提供します。

java.sql.CallableStatementを実装します。

OraclePreparedStatementを機能拡張します。

OracleResultSet

インタフェース

oracle.sql形式でデータを取り出すgetXXXメソッドを提供します。

java.sql.ResultSetを実装します。

OracleResultSetMetaData

インタフェース

列名やデータ型などのOracle結果セットのメタデータ情報を取得するメソッドを提供します。

java.sql.ResultSetMetaDataを実装します。

OracleDatabaseMetaData

クラス

データベース製品名/バージョン、表情報、デフォルト・トランザクション分離レベルなどのデータベースに関するメタデータ情報を取得するメソッドを提供します。

java.sql.DatabaseMetaDataを実装します。

OracleTypes

クラス

SQL型を識別する整数定数を定義します。

標準型の場合、同じ値を標準java.sql.Typesクラスとして使用します。さらに、Oracle拡張型に対応した定数も追加します。

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

- インタフェースoracle.jdbc.OracleConnection

- インタフェースoracle.jdbc.OracleStatement

- インタフェースoracle.jdbc.OraclePreparedStatement

- インタフェースoracle.jdbc.OracleCallableStatement

- インタフェースoracle.jdbc.OracleResultSet

- インタフェースoracle.jdbc.OracleResultSetMetaData

- クラスoracle.jdbc.OracleTypes

- メソッドgetJavaSqlConnection

インタフェースoracle.jdbc.OracleConnection

このインタフェースは、標準JDBC接続機能を拡張して、Oracle Statementオブジェクトの作成と取得、Oracleパフォーマンス拡張機能用のフラグやオプションの設定、Oracleオブジェクト用型マップのサポート、およびクライアント識別子のサポートを実施します。

Oracle Database 11gリリース1(11.1)では、Oracle Databaseインスタンスの起動と停止を実行できる新しいメソッドがこのインタフェースに追加されていました。また、OracleConnectionインタフェースでは、可視性および透明性を向上させるために、すべての接続プロパティを定数として定義します。

このインタフェースは、DATEおよびNUMBERのようなoracle.sqlデータ値を構築するために、ファクトリ・メソッドも定義します。ファクトリ・メソッドの使用時には次の点に注意してください。

- oracle.sql型のインスタンスを構築するすべてのコードで、Oracle拡張ファクトリ・メソッドを使用する必要があります。たとえば、ARRAY、BFILE、DATE、INTERVALDS、NUMBER、STRUCT、TIME、TIMESTAMPなどです。

- 標準型のインスタンスを構築するすべてのコードで、JDBC4.0標準ファクトリ・メソッドを使用する必要があります。たとえば、CLOBBLOBNCLOBなどです。

- CHAR、JAVA_STRUCT、ArrayDescriptorおよびStructDescriptorにはファクトリ・メソッドがありません。これらの型は内部ドライバの使用のためのみに用意されています。

注意:
Oracle Database 11gリリース1(11.1)より前では、引数としてARRAYおよびSTRUCTクラス・コンストラクタに渡すために、ArrayDescriptorsおよびStructDescriptorsを作成する必要がありました。新しいARRAYおよびStructファクトリ・メソッドは記述子の引数がありません。ドライバはまだ内部で記述子を使用していますが、作成する必要はありません。

クライアント識別子

クライアント識別子を接続プーリング環境で使用すると、データベース・セッションを現在使用している軽量ユーザーを識別できます。クライアント識別子を使用すると、異なるデータベース・セッション間でグローバル・アクセス・アプリケーション・コンテキストを共有することもできます。データベース・セッションで設定されたクライアント識別子は、データベース監査がオンにされたときに監査されます。

関連項目:
『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』および『Oracle Database JDBC Java APIリファレンス』

インタフェースoracle.jdbc.OracleStatement

このインタフェースは標準のJDBC文機能を拡張するもので、OraclePreparedStatementクラスとOracleCallableStatementクラスのスーパーインタフェースです。拡張された機能には、Oracleパフォーマンス拡張機能用の設定フラグとオプションの文単位でのサポートが含まれます。OracleConnectionインタフェースでは、それらを接続単位で設定していました。

インタフェースoracle.jdbc.OraclePreparedStatement

このインタフェースは、OracleStatementインタフェースを拡張し、標準JDBCのプリコンパイルされたSQL文の機能を拡張します。また、oracle.jdbc.OraclePreparedStatementインタフェースはOracleCallableStatementインタフェースによって拡張されます。拡張機能は次の機能から構成されます。

- oracle.sql.*型とオブジェクトをプリコンパイルされたSQL文にバインドするためのsetXXXメソッド

- SELECT文を実行しないで、プリコンパイルされたSQL文からメタデータを取得するためのgetMetaDataメソッド

- 文単位でOracleパフォーマンス拡張機能をサポートするためのメソッド

注意:
:NEWまたは:OLD列を参照するトリガーの作成にPreparedStatementインタフェースを使用しないでください。かわりに、Statementを使用してください。PreparedStatementを使用すると、実行が失敗し、メッセージ「java.sql.SQLException: INまたはOUTパラメータがありません - 索引:: 1」が発行されます。

インタフェースoracle.jdbc.OracleCallableStatement

このインタフェースは、OracleStatementインタフェースを拡張するOraclePreparedStatementインタフェースを機能拡張し、標準JDBCのコール可能文機能を組み込みます。

注意:
:NEWまたは:OLD列を参照するトリガーの作成にCallableStatementインタフェースを使用しないでください。かわりにStatementを使用してください。CallableStatementを使用すると、実行が失敗し、メッセージ「java.sql.SQLException: INまたはOUTパラメータがありません - 索引:: 1」が発行されます。

注意:

- setXXX(String,...)とregisterOutParameter(String,...)メソッドは、すべてのバインドがプロシージャまたは関数パラメータのみの場合にかぎり使用できます。文はそれ以外のバインドを含むことができません。パラメータ・バインドは疑問符で示す必要があります(:XXではなく、?)。

- setXXX(int,...)またはsetXXXAtName(String,...)メソッドを使用している場合、出力パラメータは、名前付きパラメータを指定するためのregisterOutParameter(String,...)ではなく、registerOutParameter(int,...)を使用してバインドされます。

インタフェースoracle.jdbc.OracleResultSet

このインタフェースは、標準JDBC結果セットの機能を拡張し、getXXXメソッドを実装してデータをoracle.sql.*オブジェクト内に取得します。

インタフェースoracle.jdbc.OracleResultSetMetaData

このインタフェースは、標準JDBC結果セットのメタデータ機能を拡張して、Oracle結果セット・オブジェクトの情報を取得します。

関連項目:
「結果セット・メタデータ拡張機能の使用方法」

クラスoracle.jdbc.OracleTypes

OracleTypesクラスは、JDBCがSQL型を識別するのに使用する定数を定義します。このクラス内の各変数は、整数の定数値を持ちます。oracle.jdbc.OracleTypesクラスには、標準Java java.sql.Typesクラスの型コード定義の複製と、次のOracle拡張機能用の補足的な型コードが含まれます。

- OracleTypes.BFILE

- OracleTypes.ROWID

- OracleTypes.CURSOR(REF CURSOR型の場合)

- OracleTypes.CHAR_BYTES(同じ列のsetNullとsetCHARメソッドをコールする場合)

java.sql.Typesの場合と同様に、変数名はすべて大文字にする必要があります。

JDBCは、OracleTypesクラスの要素によって識別されたSQL型を、出力パラメータの登録、およびPreparedStatementクラスのsetNullメソッドという2つの分野で使用します。

OracleTypesと出力パラメータの登録

java.sql.Typesまたはoracle.jdbc.OracleTypesの型コードは、java.sql.CallableStatementインタフェースおよびoracle.jdbc.OracleCallableStatementインタフェースのregisterOutParameterメソッドで出力パラメータのSQL型を識別します。

次に、CallableStatementインタフェースおよびOracleCallableStatementインタフェースでregisterOutputParameterメソッドが使用可能な形式を示します。

cs.registerOutParameter(int index, int sqlType);

cs.registerOutParameter(int index, int sqlType, String sql_name);

cs.registerOutParameter(int index, int sqlType, int scale);

これらのシグネチャでは、indexにはパラメータ索引が、sqlTypeにはSQLデータ型の型コードが入ります。sql_nameにはデータ型に与えられた名前が入りますが、sqlTypeがSTRUCT、REFまたはARRAY型コードの場合にはユーザー定義型の名前が入ります。さらに、sqlTypeがNUMERICまたはDECIMAL型コードの場合には、scaleに、小数点の右側にある桁の数が入ります。

次の例は、CallableStatementインタフェースを使用して、charoutという名前付きプロシージャをコールしています。CHARデータ型が戻されます。registerOutParameterメソッドにおけるOracleTypes.CHAR型のコードの使用に注意してください。

CallableStatement cs = conn.prepareCall ("BEGIN charout (?); END;");
cs.registerOutParameter (1, OracleTypes.CHAR);
cs.execute ();
System.out.println ("Out argument is: " + cs.getString (1));

次の例は、CallableStatementインタフェースを使用して、structoutをコールしています。STRUCTデータ型が戻されます。registerOutParameterの形式では、型コードにTypes.STRUCTまたはOracleTypes.STRUCT、SQL名にEMPLOYEEを指定する必要があります。

この例では、EMPLOYEE型でいかなる型マップも宣言されていないことを前提としているため、STRUCTデータ型内に取得されます。oracle.sql.STRUCTオブジェクトとしてEMPLOYEEの値を取り出すために、Statemenオブジェクトcsは、OracleCallableStatementにキャストされ、Oracle拡張機能getSTRUCTメソッドが実行されます。

CallableStatement cs = conn.prepareCall ("BEGIN structout (?); END;");
cs.registerOutParameter (1, OracleTypes.STRUCT, "EMPLOYEE");
cs.execute ();

// get the value into a STRUCT because it
// is assumed that no type map has been defined
STRUCT emp = ((OracleCallableStatement)cs).getSTRUCT (1);

OracleTypesおよびsetNullメソッド

TypesおよびOracleTypesでの型コードは、データ項目のSQL型を特定します。setNullメソッドがそれをNULLに設定します。setNullメソッドは、java.sql.PreparedStatementインタフェースとoracle.jdbc.OraclePreparedStatementインタフェースにあります。

次に、PreparedStatementおよびOraclePreparedStatementオブジェクトでsetNullメソッドが使用可能な形式を示します。

ps.setNull(int index, int sqlType);

ps.setNull(int index, int sqlType, String sql_name);

これらのシグネチャでは、indexがパラメータ索引を表します。sqlTypeはSQLデータ型のための型コードです。sql_nameは、sqlTypeがSTRUCT、REFまたはARRAY型コードである場合に、ユーザー定義のデータ型に対して指定される名前です。無効なsqlTypeを入力すると、ParameterTypeConflict例外がスローされます。

次の例では、プリコンパイルされたSQL文を使用してNULL値をデータベースに挿入します。NULLに設定する数値オブジェクトの識別にはOracleTypes.NUMERICを使用することに注意してください。ただし、Types.NUMERICも使用されることがあります。

PreparedStatement pstmt =
conn.prepareStatement ("INSERT INTO num_table VALUES (?)");

pstmt.setNull (1, OracleTypes.NUMERIC);
pstmt.execute ();

この例では、プリコンパイルされたSQL文を使用して、EMPLOYEE型のNULL STRUCTオブジェクトをデータベースに挿入します。

PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO employee_table VALUES (?)");

pstmt.setNull (1, OracleTypes.STRUCT, "EMPLOYEE");
pstmt.execute ();

同じ列のsetCHARメソッドもコールする場合、OracleTypes.CHAR_BYTES型をsetNullメソッドで使用することもできます。たとえば、次のようになります。

ps.setCHAR(n, aCHAR);
ps.addBatch();
ps.setNull(n, OracleTypes.CHAR_BYTES);
ps.addBatch();

この例では、OracleTypes.CHAR_BYTES型以外のどの型を使用しても、データベースとの余計なラウンドトリップが発生します。また、setNullメソッドを使用しないでコードを記述することもできます。たとえば、次の例のようにコードを記述することもできます。

ps.setCHAR(n, null);

メソッドgetJavaSqlConnection

oracle.sql.*クラスのgetJavaSqlConnectionメソッドはjava.sql.Connectionを戻します。このメソッドは、次のOracleデータ型クラスで使用できます。

注意:
Oracle 8iおよびJDBCの以前のバージョンで使用されていたgetConnectionメソッドはoracle.jdbc.driver.OracleConnectionを戻します。Oracle 9iリリースのoracle.jdbcパッケージを優先して、oracle.jdbc.driverパッケージでのクラスの使用は非推奨になりました。Oracle Database 11gリリース1(11.1)から、パッケージoracle.jdbc.driverのクラスがサポート対象外になりました。

- oracle.sql.ARRAY

- oracle.sql.BFILE

- oracle.sql.BLOB

- oracle.sql.CLOB

- oracle.sql.OPAQUE

- oracle.sql.REF

- oracle.sql.STRUCT

次のコードは、ArrayクラスのgetJavaSqlConnectionメソッドを示しています。

public class ARRAY
{
java.sql.Connection getJavaSqlConnection()
throws SQLException;
...
}

DML RETURNING

DML RETURNING機能は、自動生成キーの取出しに比べて、より豊富な機能を提供します。この機能は、自動生成キーの取出しに使用できますが、アプリケーションで使用する可能性がある他の列や値の取出しにも使用できます。

注意:

- サーバー側内部ドライバは、DML RETURNINGおよび自動生成キーの取出しをサポートしていません。

- 同一文中でDML RETURNINGと自動生成キーの取得の両方を使用することはできません。

次の各項では、DML RETURNING機能のサポートについて説明します。

- Oracle固有のAPI

- DML RETURNING文の実行

- DML RETURNINGの例

- DML RETURNINGの制限事項

関連項目:
「自動生成キーの取出し」

Oracle固有のAPI

OraclePreparedStatementインタフェースは、DML RETURNINGをサポートするOracle固有のApplication Program Interface(API)に伴って機能拡張されました。DML RETURNINGによって戻されるパラメータおよび取り出されるデータを登録するために、registerReturnParameterメソッドおよびgetReturnResultSetメソッドがoracle.jdbc.OraclePreparedStatementインタフェースに追加されています。

DML RETURNING機能の戻りパラメータは、registerReturnParameterメソッドを使用して登録します。エラーが発生した場合、メソッドはSQLExceptionインスタンスをスローします。戻りパラメータの索引を指定する正の整数を渡す必要があります。また、戻りパラメータの型も指定する必要があります。戻りパラメータの最大バイト数または最大文字数も指定できます。このメソッドは、charまたはRAW型でのみ使用できます。SQL構造型の完全修飾名も指定できます。

注意:
戻りパラメータの最大サイズが不明な場合は、デフォルトの最大サイズを選択するregisterReturnParameter(int paramIndex, int externalType)を使用してください。戻りパラメータの最大サイズが判明している場合は、registerReturnParameter(int paramIndex, int externalType, int maxSize)を使用することでメモリー消費を抑制できます。

getReturnResultSetメソッドは、DML RETURNING機能で戻されたデータをフェッチし、ResultSetオブジェクトとして戻します。エラーが検出された場合は、SQLException例外が発生します。

注意:
DML RETURNING機能のためのOracle固有のAPIは、Java Development Kit(JDK)1.5の場合はojdbc5.jar、JDK 1.6の場合はojdbc6.jarに含まれています。

DML RETURNING文の実行

DML RETURNING文を実行する前に、JDBCアプリケーションが、registerReturnParameterメソッドを1つ以上コールする必要があります。これらのメソッドは、戻りパラメータに関する型やサイズなどの情報をJDBCドライバに提供します。DML RETURNING文は、executeUpdateまたはexecuteのいずれかの標準JDBC APIを使用して処理されます。戻されたパラメータは、oracle.jdbc.OraclePreparedStatementインタフェースのgetReturnResultSetメソッドを使用して、ResultSetオブジェクトとしてフェッチできます。

ResultSetオブジェクトの値を読み取るには、基礎となるStatementオブジェクトをオープンする必要があります。基礎となるStatementオブジェクトがクローズされている場合は、戻されたResultSetオブジェクトもクローズ状態となります。この状態は、SQL問合せ文を処理することで取り出されたResultSetオブジェクトの状態と一致します。

DML RETURNING文を実行する場合、getReturnResultSetメソッドで戻されるResultSetオブジェクトの同時実行性はCONCUR_READ_ONLYであり、そのResultSetオブジェクト型はTYPE_FORWARD_ONLYまたはTYPE_SCROLL_INSENSITIVEである必要があります。

DML RETURNINGの例

ここでは、DML RETURNING機能に関する2つのコード例を示します。

次のコードは、DML RETURNING機能の使用例です。この例では、name列の最大サイズを100文字と仮定します。name列の最大サイズが判明しているため、registerReturnParameter(int paramIndex, int externalType, int maxSize)メソッドを使用します。

...
OraclePreparedStatement pstmt = (OraclePreparedStatement)conn.prepareStatement(
"delete from tab1 where age < ? returning name into ?");
pstmt.setInt(1,18);

/** register returned parameter
* in this case the maximum size of name is 100 chars
*/
pstmt.registerReturnParameter(2, OracleTypes.VARCHAR, 100);

// process the DML returning statement
count = pstmt.executeUpdate();
if (count>0)
{
ResultSet rset = pstmt.getReturnResultSet(); //rest is not null and not empty
while(rset.next())
{
String name = rset.getString(1);
...
}
}
...

次のコードも、DML RETURNING機能の使用例です。ただし、この例では、戻りパラメータの最大サイズが不明です。したがって、registerReturnParameter(int paramIndex, int externalType)メソッドを使用します。

...
OraclePreparedStatement pstmt = (OraclePreparedStatement)conn.prepareStatement(
"insert into lobtab values (100, empty_clob()) returning col1, col2 into ?, ?");

// register return parameters
pstmt.registerReturnParameter(1, OracleTypes.INTEGER);
pstmt.registerReturnParameter(2, OracleTypes.CLOB);

// process the DML returning SQL statement
pstmt.executeUpdate();
ResultSet rset = pstmt.getReturnResultSet();
int r;
CLOB clob;
if (rset.next())
{
r = rset.getInt(1);
System.out.println(r);
clob = (CLOB)rset.getClob(2);
...
}
...

DML RETURNINGの制限事項

DML RETURNING機能を使用する場合は、次の点に注意してください。

- getReturnResultSetメソッドを複数回起動した場合は、その戻り値が不正確になります。そのため、これに関連するアクションには依存しないようにします。

- DML RETURNING文の実行で戻るResultSetオブジェクトは、ResultSetMetaData型をサポートしません。したがって、アプリケーションでは、DML RETURNING文を実行する前に、戻りパラメータの情報を把握している必要があります。

- DML RETURNINGでは、ストリームはサポートされません。

- DML RETURNING機能をバッチ更新と組み合せることはできません。

- 単一のSQL DML文の中で自動生成キー機能とDML RETURNING機能を両方とも使用することはできません。たとえば、次のような使用方法は許可されません。

...
PreparedStatement pstmt = conn.prepareStatement('insert into orders (?, ?, ?) returning order_id into ?");
pstmt.setInt(1, seq01.NEXTVAL);
pstmt.setInt(2, 100);
pstmt.setInt(3, 966431502);
pstmt.registerReturnParam(4, OracleTypes.INTEGER);
pstmt.executeUpdate;
ResultSet rset = pstmt.getGeneratedKeys;
...

PL/SQL索引付き表へのアクセス

Oracle JDBCドライバを使用すると、JDBCアプリケーションで、索引付き表パラメータを使用してPL/SQLをコールできます。この項の内容は次のとおりです。

- 概要

- INパラメータのバインド

- OUTパラメータの受取り

- 型マッピング

注意:
PL/SQLレコードの索引付き表はサポートされません。

概要

Oracle JDBCドライバは、スカラー・データ型のPL/SQL索引付き表をサポートします。表4-2は、サポートされるスカラー型とそれに対応するJDBC型コードを示しています。

表4-2 PL/SQL型と対応するJDBC型

PL/SQL型

JDBC型

BINARY_INTEGER

NUMERIC

NATURAL

NUMERIC

NATURALN

NUMERIC

PLS_INTEGER

NUMERIC

POSITIVE

NUMERIC

POSITIVEN

NUMERIC

SIGNTYPE

NUMERIC

STRING

VARCHAR

注意:
Oracle JDBCは、要素型としてRAW、DATEおよびPL/SQL RECORDをサポートしません。

通常のOracle JDBC入力バインド、出力登録、およびデータアクセス・メソッドは、PL/SQL索引付き表をサポートしません。この章では、これらの型をサポートするための追加のメソッドについて説明します。

OraclePreparedStatementおよびOracleCallableStatementクラスは、追加のメソッドを定義します。これらのメソッドには次のものがあります。

- setPlsqlIndexTable

- registerIndexTableOutParameter

- getOraclePlsqlIndexTable

- getPlsqlIndexTable

これらのメソッドは、PL/SQL索引付き表をIN、OUTまたはIN OUTパラメータとして、ファンクション戻り値も含めて処理します。

関連項目:
Oracle Database PL/SQL言語リファレンス

INパラメータのバインド

PL/SQL索引付き表パラメータをINパラメータ・モードでバインドするには、OraclePreparedStatementおよびOracleCallableStatementの各クラスで定義されたsetPlsqlIndexTableメソッドを使用します。

synchronized public void setPlsqlIndexTable (int paramIndex, Object arrayData, int maxLen, int curLen, int elemSqlType,
int elemMaxLen) throws SQLException

表4-3では、getPlsqlIndexTableメソッドの引数について説明しています。

表4-3 setPlsqlIndexTableメソッドの引数

引数

説明

int paramIndex

文内のパラメータの位置を示します。

Object arrayData

PL/SQL索引付き表パラメータにバインドされる値の配列です。この値はjava.lang.Object型に関する値です。この値には、int[]などのJavaプリミティブ型配列、またはBigDecimal[]などのJavaオブジェクト配列を指定できます。

int maxLen

一括更新で利用できる最大のcurLenを定義する、索引付き表バインド値の表の最大長を指定します。スタンドアロンのバインドの場合、maxLenにはcurLenと同じ値を使用してください。この引数は必須です。

int curLen

arrayDataの索引付き表バインド値の実際のサイズを指定します。curLen値がarrayDataのサイズより小さい場合は、curLenで指定した数の表要素のみがデータベースに渡されます。curLen値がarrayDataのサイズよりも大きい場合は、arrayData全体がデータベースに送信されます。

int elemSqlType

OracleTypesクラスに定義されている値に基づいて、索引付き表の要素型を指定します。

int elemMaxLen

要素型がCHAR、VARCHARまたはRAWである場合に索引付き表の要素の最大長を指定します。この値は、他の型では無視されます。

次のコード例では、setPlsqlIndexTableメソッドを使用して、索引付き表をINパラメータとしてバインドします。

// Prepare the statement
OracleCallableStatement procin = (OracleCallableStatement)
conn.prepareCall ("begin procin (?); end;");

// index-by table bind value
int[] values = { 1, 2, 3 };

// maximum length of the index-by table bind value. This
// value defines the maximum possible "currentLen" for batch
// updates. For standalone binds, "maxLen" should be the
// same as "currentLen".
int maxLen = values.length;

// actual size of the index-by table bind value
int currentLen = values.length;

// index-by table element type
int elemSqlType = OracleTypes.NUMBER;

// index-by table element length in case the element type
// is CHAR, VARCHAR or RAW. This value is ignored for other
// types.
int elemMaxLen = 0;

// set the value
procin.setPlsqlIndexTable (1, values,
maxLen, currentLen,
elemSqlType, elemMaxLen);

// execute the call
procin.execute ();

OUTパラメータの受取り

この項では、PL/SQL索引付き表をOUTパラメータとして登録する方法について説明します。また、様々なマッピング・スタイルでOUTバインド値にアクセスする方法について説明します。

注意:
この項で説明するメソッドは、ファンクション戻り値およびIN OUTパラメータ・モードに適用されます。

OUTパラメータの登録

PL/SQL索引付き表をOUTパラメータとして登録するには、OracleCallableStatementクラスで定義されたregisterIndexTableOutParameterメソッドを使用します。

synchronized public void registerIndexTableOutParameter     (int paramIndex, int maxLen, int elemSqlType,
int elemMaxLen) throws SQLException

表4-4では、registerIndexTableOutParameterメソッドの引数について説明しています。

表4-4 registerIndexTableOutParameterメソッドの引数

引数

説明

int paramIndex

文内のパラメータの位置を示します。

int maxLen

戻される索引付き表バインド値の表の最大長を指定します。

int elemSqlType

OracleTypesクラスに定義されている値に基づいて、索引付き表の要素型を指定します。

int elemMaxLen

要素型がCHAR、VARCHARまたはFIXED_CHARである場合に索引付き表の要素の最大長を指定します。この値は、他の型では無視されます。

次のコード例では、registerIndexTableOutParameterメソッドを使用して、索引付き表をOUTパラメータとして登録します。

// maximum length of the index-by table value. This
// value defines the maximum table size to be returned.
int maxLen = 10;

// index-by table element type
int elemSqlType = OracleTypes.NUMBER;

// index-by table element length in case the element type
// is CHAR, VARCHAR or FIXED_CHAR. This value is ignored for other
// types
int elemMaxLen = 0;

// register the return value
funcnone.registerIndexTableOutParameter
(1, maxLen, elemSqlType, elemMaxLen);

OUTパラメータ値へのアクセス

OUTバインド値へアクセスするために、OracleCallableStatementクラスでは、様々なマッピング・スタイルの索引付き表の値を戻す複数のメソッドを定義します。JDBCドライバでは、次の3つのマッピングを選択できます。

マッピング

使用するメソッド

JDBCデフォルト・マッピング

getPlsqlIndexTable(int)

Oracleマッピング

getOraclePlsqlIndexTable(int)

Javaプリミティブ型マッピング

getPlsqlIndexTable(int, Class)

型マッピング

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

- JDBCデフォルト・マッピング

- Oracleマッピング

- Javaプリミティブ型マッピング

JDBCデフォルト・マッピング

getPlsqlIndexTable(int)メソッドは、JDBCデフォルト・マッピングを使用して索引付き表の要素を戻します。このメソッドの構文は次のとおりです。

public Object getPlsqlIndexTable (int paramIndex)
throws SQLException

表4-5では、getPlsqlIndexTableメソッドの引数について説明しています。

表4-5 getPlsqlIndexTableメソッドの引数

引数

説明

int paramIndex

この引数は、文内のパラメータの位置を示します。

戻り値はJava配列です。この配列の要素は、要素のSQL型に対応するデフォルトのJava型です。たとえば、NUMERIC型コードの要素による索引付き表の場合、要素値はOracle JDBCドライバによってBigDecimalにマップされ、getPlsqlIndexTableメソッドがBigDecimal[]配列を戻します。JDBCアプリケーションの場合、戻り値をBigDecimal[]にキャストして表要素値にアクセスする必要があります。

次のコード例では、getPlsqlIndexTableメソッドを使用して、JDBCデフォルト・マッピングで索引付き表の要素を戻します。

// access the value using JDBC default mapping
BigDecimal[] values =
(BigDecimal[]) procout.getPlsqlIndexTable (1);

// print the elements
for (int i=0; i<values.length; i++)
System.out.println (values[i].intValue());

Oracleマッピング

getOraclePlsqlIndexTableメソッドは、Oracleマッピングを使用して索引付き表要素を戻します。

public Datum[] getOraclePlsqlIndexTable (int paramIndex)
throws SQLException

表4-6では、getOraclePlsqlIndexTableメソッドの引数について説明しています。

表4-6 getOraclePlsqlIndexTableメソッドの引数

引数

説明

int paramIndex

文内のパラメータの位置を示します。

戻り値はoracle.sql.Datum配列で、配列の要素は、要素のSQL型に対応するデフォルトのDatum型です。たとえば、数値要素の索引付き表の要素値は、Oracleマッピングでoracle.sql.NUMBER型にマップされ、getOraclePlsqlIndexTableメソッドはoracle.sql.NUMBER要素を含むoracle.sql.Datum配列を戻します。

次のコード例では、getOraclePlsqlIndexTableメソッドを使用して、PL/SQL索引付き表のOUTパラメータの要素に、Oracleマッピングを使用してアクセスします。

// Prepare the statement
OracleCallableStatement procout = (OracleCallableStatement)
conn.prepareCall ("begin procout (?); end;");

...

// run the call
procout.execute ();

// access the value using Oracle JDBC mapping
Datum[] outvalues = procout.getOraclePlsqlIndexTable (1);

// print the elements
for (int i=0; i<outvalues.length; i++)
System.out.println (outvalues[i].intValue());

Javaプリミティブ型マッピング

getPlsqlIndexTable(int, Class)メソッドは、Javaプリミティブ型の索引付き表の要素を戻します。戻り値はJava配列です。このメソッドの構文は次のとおりです。

synchronized public Object getPlsqlIndexTable    (int paramIndex, Class primitiveType) throws SQLException

表4-7では、getPlsqlIndexTableメソッドの引数について説明しています。

表4-7 getPlsqlIndexTableメソッドの引数

引数

説明

int paramIndex

文内のパラメータの位置を示します。

Class primitiveType

索引付き表の要素の変換先となるJavaプリミティブ型を指定します。たとえば、java.lang.Integer.TYPEを指定すると、戻り値はint配列になります。

このパラメータには、次の値を指定できます。

java.lang.Integer.TYPE

java.lang.Long.TYPE

java.lang.Float.TYPE

java.lang.Double.TYPE

java.lang.Short.TYPE

次のコード例では、getPlsqlIndexTableメソッドを使用して、数値のPL/SQL索引付き表の要素にアクセスします。この例では、2つ目のパラメータはjava.lang.Integer.TYPEを指定し、getPlsqlIndexTableメソッドはint配列を戻します。

OracleCallableStatement funcnone = (OracleCallableStatement)
conn.prepareCall ("begin ? := funcnone; end;");

// maximum length of the index-by table value. This
// value defines the maximum table size to be returned.
int maxLen = 10;

// index-by table element type
int elemSqlType = OracleTypes.NUMBER;

// index-by table element length in case the element type
// is CHAR, VARCHAR or RAW. This value is ignored for other
// types
int elemMaxLen = 0;

// register the return value
funcnone.registerIndexTableOutParameter (1, maxLen,
elemSqlType, elemMaxLen);
// execute the call
funcnone.execute ();

// access the value as a Java primitive array.
int[] values = (int[])
funcnone.getPlsqlIndexTable (1, java.lang.Integer.TYPE);

// print the elements
for (int i=0; i<values.length; i++)
System.out.println (values[i]);

5 JDBC Thin固有の機能

この章では、Java Database Connectivity(JDBC)Thinクライアントの概要、およびJDBC Thinドライバのみでサポートされている機能について説明します。Oracle JDBCアプレットを使用する上での基本情報も提供します。この章の内容は次のとおりです。

- JDBC Thinクライアントの概要

- サポートする追加機能

- アプレット内のJDBC

JDBC Thinクライアントの概要

JDBC Thinクライアントは、pure JavaのType IVドライバです。このドライバは軽量で、インストールも簡単です。このドライバは、JDBC Oracle Call Interface(OCI)ドライバのパフォーマンスに匹敵する高いパフォーマンスを提供します。JDBC Thinドライバは、すべてJavaで記述されており、プラットフォームに依存しません。また、クライアント側に追加のOracleソフトウェアは必要ありません。

JDBC Thinドライバは、Oracle DatabaseからデータにアクセスするためにOracleによって開発されたプロトコル、TTCを使用しているサーバーと通信します。アプリケーション・サーバーとアプレットに対して使用できます。このドライバは、Javaソケットの上にOracle NetとTTCを実装するTCP/IPの実装を提供することにより、データベースへの直接接続を可能とします。このプロトコルはどちらも、対応するサーバー上のプロトコルの軽量版実装です。Oracle NetプロトコルはTCP/IP経由でのみ実行されます。

JDBC Thinドライバは、クライアント側とサーバー側の両方で使用できます。クライアント側では、ドライバは、クライアント上または3層構成の中間層で実行されているJavaアプリケーションやJavaアプレットで使用できます。サーバー側では、このドライバが、リモートのOracle Databaseインスタンスまたは同じデータベースの別のセッションへのアクセスに使用されます。

サポートする追加機能

JDBC Thinドライバは、標準JDBC機能のすべてをサポートします。JDBC Thinドライバは、次の追加機能に対するサポートも提供しています。

- アプレットのサポート

- ネイティブXAのデフォルトでのサポート

アプレットのサポート

このJDBC Thinドライバは、アプレットに対するサポートを提供する唯一のOracle JDBCドライバです。このドライバは、ブラウザで実行するJavaアプレットとともにダウンロードできます。

注意:
JDBC Thinドライバをアプレットと併用する場合は、クライアント側で使用するブラウザがJavaソケットをサポートしている必要があります。

HTTPプロトコルはステートレスで、通常はネットワークを介した通信に使用されます。ただし、JDBC Thinドライバはステートレスではありません。したがって、アプレットおよびJDBC Thinドライバをダウンロードする最初のHTTP要求はステートレスになります。JDBC Thinドライバがデータベース接続を確立すると、ブラウザとデータベース間の通信はステートフルになり、2層構成となります。

関連項目:
「アプレット内のJDBC」

ネイティブXAのデフォルトでのサポート

JDBC Thinドライバには、JDBC OCIドライバと同様にネイティブXAに対するサポートが用意されています。ただし、JDBC ThinドライバはデフォルトでネイティブXAをサポートします。この点は、ネイティブXAのサポートをデフォルトでは使用できないJDBC OCIドライバと異なります。

関連項目:
「Oracle JDBCドライバのネイティブXA」

アプレット内のJDBC

アプレットには、Oracle JDBC Thinドライバのみを使用できます。この項では、アプレットをデータベースに接続するために必要な操作について説明します。これには、Webサーバーとは別のホストで動作しているデータベースに接続する場合に、Oracle DatabaseのConnection Manager機能または署名付きアプレットを使用する方法が含まれます。また、ファイアウォールを通過してアプレットをデータベースに接続する方法についても説明します。最後に、アプレットをパッケージ化およびデプロイする方法について説明します。

内容は次のとおりです。

- アプレットを介したデータベースへの接続

- Webサーバーとは異なるホスト上のデータベースへの接続

- ファイアウォールとアプレットの使用方法

- アプレットのパッケージ化

- HTMLページでのアプレットの指定

アプレットを介したデータベースへの接続

JDBCドライバを使用したアプレットの最も一般的な作業は、データベースへの接続と問合せです。アプレットのセキュリティ上の制限のため、特定の処理を実行せずにアプレットがオープンできるのは、ダウンロード元のホストへのTCP/IPソケットのみです。この場合のホストは、Webサーバーが実行されているホストを意味します。つまり、特定の処理を行わない場合、アプレットが接続できるのは、Webサーバーと同じホスト上で動作するデータベースのみです。

データベースとWebサーバーが同じホストで動作している場合は、問題はなく処理は必要ありません。アプリケーションから接続する場合と同様に、データベースに接続できます。

アプリケーションから接続する場合と同様に、接続情報をドライバに指定する方法は2つあります。host:port:sidの形式またはTNSキーワード値構文の形式で指定できます。

たとえば、接続するデータベースがポート1521、ホストprodHost、SID(System Identifier)ORCLで、ユーザー名をscott、パスワードをtigerとして接続する場合は、次のいずれかの接続文字列を使用します。

- host:port:sid構文を使用する場合は、次のようになります。

String connString="jdbc:oracle:thin:@prodHost:1521:ORCL";

OracleDataSource ods = new OracleDataSource();
ods.setURL(connString);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

- TNSキーワード値構文を使用する場合は、次のようになります。

String connString = "jdbc:oracle:thin:@(description=(address_list=(address=(protocol=tcp)
(port=1521)(host=prodHost)))(connect_data=(INSTANCE_NAME=ORCL)))";
OracleDataSource ods = new OracleDataSource();

ods.setURL(connString);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

TNSキーワード値ペアを使用してJDBC Thinドライバに接続情報を指定する場合は、プロトコルをTCPとして宣言する必要があります。

ただし、Webサーバーとデータベース・サーバーは、いずれも多くのリソースを必要とします。両方のサーバーが同じコンピュータ上で実行されることはほとんどありません。通常、アプレットはWebサーバーが実行されているホストとは別のホスト上のデータベースに接続します。別のコンピュータで実行中のデータベースにアプレットで接続するには、次の方法があります。

- ホスト・コンピュータ上でOracle Connection Managerを使用します。アプレットをConnection Managerに接続し、Connection Managerから別のコンピュータ上のデータベースに接続します。

- 署名付きアプレットを使用すると、他のコンピュータへのソケット接続権限を要求できます。

アプレットで、Oracle DatabaseのAdvanced Securityオプションのデータ暗号化および整合性チェックサム機能も利用できます。

Webサーバーとは異なるホスト上のデータベースへの接続

Webサーバーが動作しているホスト以外のホスト上のデータベースに接続する場合は、アプレットのセキュリティの制限に対処する必要があります。次の方法で対処できます。

- Oracle Connection Managerの使用

- 署名付きアプレットの使用

Oracle Connection Managerの使用

Oracle Connection Managerは、Oracle Netパケットを受信して別のサーバーに再転送できる軽量でスケーラブルなプログラムです。Oracle Netを実行するクライアントからは、Connection Managerはまるでデータベース・サーバーのように見えます。JDBC Thinドライバを使用するアプレットは、Webサーバー・ホスト上で実行中のConnection Managerに接続し、Connection Managerを使用して、Oracle Netパケットを異なるホスト上で動作するOracleサーバーにリダイレクトできます。

図5-1は、アプレット、Oracle Connection Managerおよびデータベースの関係を示しています。

図5-1 アプレット、Connection Managerおよびデータベースの関係

「図5-1 アプレット、Connection Managerおよびデータベースの関係」の説明

Oracle Connection Managerを使用するには、次のような2つの手順を実行する必要があります。

- Connection Managerのインストールおよび実行。

- Connection Managerをターゲットにした接続文字列の記述。

Oracle Connection Managerのインストールおよび実行

Oracle配布メディアに格納されているConnection ManagerをWebサーバー・ホストにインストールする必要があります。

Webサーバー・ホストでは、ORACLE_HOME/NET8/ADMINディレクトリにCMAN.ORAファイルを作成します。CMAN.ORAファイル内には、ファイアウォールおよび接続プーリングのサポートなどのオプションも宣言できます。

次に、非常に単純なCMAN.ORAファイルの例を示します。web-server-hostを使用するWebサーバー・ホストの名前に置き換えてください。ファイルの4行目は、Connection Managerがポート1610をリスニングしていることを示しています。これと同じポート番号をJDBCの接続文字列に使用する必要があります。

cman = (ADDRESS_LIST =
(ADDRESS = (PROTOCOL=TCP)
(HOST=web-server-host)
(PORT=1610)))

cman_profile = (parameter_list =
(MAXIMUM_RELAYS=512)
(LOG_LEVEL=1)
(TRACING=YES)
(RELAY_STATISTICS=YES)
(SHOW_TNS_INFO=YES)
(USE_ASYNC_CALL=YES)
(AUTHENTICATION_LEVEL=0)
)

ファイルの作成後、オペレーティング・システムのプロンプトで次のコマンドを使用してConnection Managerを起動します。

cmctl start

アプレットを使用するには、この時点でアプレット用の接続文字列を記述する必要があります。

Connection ManagerをターゲットにしたURLの記述

ここでは、アプレットがConnection Managerに接続し、Connection Managerがデータベースに接続するようにURLを記述する方法について説明します。URLには、Connection Managerが実行されているWebサーバー・ホストのプロトコル、ポートおよびホスト名を示したアドレス・リストの後に、データベースが実行されているホストのプロトコル、ポートおよびホスト名を指定します。

次の例では、図5-1で示した構成について説明します。Connection Managerを実行しているWebサーバーは、ホストwebHostにあり、ポート1610をリスニングしています。接続対象のデータベースは、ポート1521をリスニングし、SIDがORCLであるホストoraHost上にあります。URLをTNSキーワード値形式で次のように記述します。

String myURL =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1610)(host=webHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(INSTANCE_NAME=orcl))
(source_route=yes))";
OracleDataSource ods = new OracleDataSource();
ods.setURL(myURL);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

address_listエントリの先頭要素は、Connection Managerに対する接続を表します。2番目の要素は、接続するデータベースを表します。アドレスをリストする順序は重要です。

アプレットで前述のようなURLを使用した場合、そのアプレットはホストoraHost上のデータベースに直接接続したかのように機能します。

複数のConnection Manager経由の接続

アプレットは、複数のConnection Managerを経由してターゲット・データベースに接続することもできます。たとえば、Connection Managerがプロキシ連鎖を形成している場合があります。これを行うには、Connection Managerのアドレスをアクセスする順番にアドレス・リストに追加します。データベース・リスナーは、このリストの最後のアドレスにする必要があります。

署名付きアプレットの使用

Java Development Kit(JDK)1.2.xベース以上のブラウザでは、アプレットはソケット接続権限を要求し、Webサーバー・ホストとは異なるホストで動作しているデータベースに接続できます。Netscape 4.0以上では、アプレットに署名、つまり署名付きアプレットを記述することで、これを実行できます。次の手順を実行する必要があります。

1. アプレットに署名します。アプレットに署名するために実行する必要のある手順については、次のWebサイトを参照してください。
http://www.oracle.com/technetwork/java/index.html

2. ソケットをオープンする前に適切な権限を要求するアプレット・コードを含めます。
Netscapeを使用している場合は、コードに次のような文を含めます。

netscape.security.PrivilegeManager.enablePrivilege("UniversalConnect");
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:scott/tiger@dlsun511:1721:orcl");
Connection conn = ods.getConnection();

3. オブジェクト署名証明書を取得する必要があります。証明書の取得とインストールについての情報があるサイトを参照してください。

署名付きアプレットの例を含むJava Security APIについては、次のSun社のサイトを参照してください。

http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136007.html

ファイアウォールとアプレットの使用方法

標準的な状況では、JDBC Thinドライバを使用したアプレットは、ファイアウォールを通過してデータベースにアクセスできません。一般的に、ファイアウォールは、権限を与えられていないクライアントによるサーバーへのアクセスを防ぐことを目的としています。データベースに接続しようとするアプレットに対し、ファイアウォールはデータベースへのTCP/IPソケットをオープンしないようにします。

一般に、ファイアウォールは規則に従っています。ファイアウォールには、接続が可能なクライアントと不可能なクライアントを定義する規則のリストがあります。ファイアウォールはこの規則とクライアントのホスト名を比較し、この比較に基づいてクライアントにアクセスを許可または禁止します。ホスト名の検索に失敗した場合、ファイアウォールは再度検索を試みます。今度は、クライアントのIPアドレスを抽出して、それを規則と比較します。ファイアウォールはこのように設計されているので、ユーザーはホスト名とIPアドレスを含んだ規則を指定できます。

ファイアウォールに関する問題は、Oracle Netに準拠したファイアウォールおよびそのファイアウォール構成に応じた接続文字列を使用することによって解決できます。Oracle Netに準拠したファイアウォールは、多数の主要なベンダーから入手できます。

署名付きでないアプレットは、そのアプレットのダウンロード元ホストにのみアクセスできます。この場合、そのホストには、Oracle Netに準拠したファイアウォールがインストールされている必要があります。これに対し、署名付きアプレットは任意のホストに接続できます。この場合、ターゲット・ホスト上のファイアウォールがアクセスを制御します。

ファイアウォールを通過して接続するには、次の項で説明する2つの処理を行う必要があります。

- JDBC Thinドライバを使用するアプレット用のファイアウォールの構成

- ファイアウォールを通過する接続のためのURLの記述

JDBC Thinドライバを使用するアプレット用のファイアウォールの構成

この項の説明では、Oracle Netに準拠したファイアウォールを実行していることを前提としています。

Javaアプレットはローカル・システムにはアクセスできません。セキュリティ上の制限のため、アプレットはローカル・システムでホスト名または環境変数を取得できません。この結果、JDBC Thinドライバはドライバが動作するホストのホスト名にアクセスできません。ファイアウォールにはホスト名が提供されません。JDBC Thinクライアントからの要求がファイアウォールを通過するには、ファイアウォールの規則のリストに対して次の操作が必要です。

- JDBCアプレットが実行されているホストのIPアドレス(ホスト名ではない)を追加します。

- ファイアウォールの規則内にホスト名「__jdbc__」が記述されていないことを確認します。このホスト名は、IPアドレスの検索を強制的に行うために、ドライバ内に模擬ホスト名としてハードコードされています。このホスト名を規則のリスト内に入力した場合は、JDBC Thinドライバを使用するすべてのアプレットがファイアウォールを通過できるようになります。

ファイアウォールを通過する接続のためのURLの記述

ファイアウォールを通過して接続できるURLを記述するには、接続先ファイアウォール・ホスト名およびデータベース・ホスト名を指定する必要があります。

たとえば、ポート1521をリスニングし、SIDがORCLであるホストoraHost上にあるデータベースに接続し、ポート1610をリスニングしているホストfireWallHost上にあるファイアウォールを通過する場合は、次のURLを使用します。

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:" +
"@(description=(address_list=" +
(address=(protocol=tcp)(host=<firewall-host>)(port=1610))" +
"(address=(protocol=tcp)(host=oraHost)(port=1521)))" +
"(source_route=yes)" +
"(connect_data=(SERVICE_NAME=orcl)))");
);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

注意:
ファイアウォールを通過して接続するために、host:port:sid構文内にURLを指定できません。たとえば、次のように指定したURLは機能しません。

String connString =
"jdbc:oracle:thin:@example.us.oracle.com:1521:orcl";

OracleDataSource ods = new OracleDataSource();
ods.setURL(connString);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

address_listの最初の要素は、ファイアウォールへの接続を表します。2番目の要素は、接続するデータベースを表します。アドレスを指定する順序が重要なので注意してください。

前述のURLは、次の形式でも記述できます。

String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1600)(host=fireWallHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(INSTANCE_NAME=orcl))
(source_route=yes))";
OracleDataSource ods = new OracleDataSource();
ods.setURL(connString);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

前述のようなURLを使用するアプレットは、ホストoraHost上のデータベースに接続されているかのように動作します。

注意:
前述の例に示したすべてのパラメータが必要です。address_listでは、ファイアウォール・アドレスは、データベース・サーバー・アドレスよりも先に指定する必要があります。

アプレットのパッケージ化

アプレットのコーディング後は、パッケージ化してユーザーが利用できるようにする必要があります。アプレットをパッケージ化するには、アプレット・クラス・ファイルとojdbc5.jarファイルまたはojdbc6.jarファイルに含まれているJDBCドライバ・クラス・ファイルが必要です。

次の手順を実行します。

1. JDBCドライバのクラス・ファイルojdbc5.jarまたはojdbc6.jarを空のディレクトリに移動します。
アプレットがUS7ASCIIまたはWE8ISO8859P1以外のキャラクタ・セットのデータベースに接続してOracleオブジェクト型を使用する場合は、orai18n.jarファイルも同じディレクトリに移動します。

2. アプレットのクラス・ファイルおよびアプレットで必要になる可能性のあるファイルをすべてこのディレクトリに追加します。

3. アプレットのクラスおよびドライバのクラスをまとめて1つのZIPファイルまたはJavaアーカイブ(JAR)ファイルにします。この1つの圧縮ファイルには、次のものを入れてください。

- ojdbc5.jarファイルまたはojdbc6.jarファイルからのクラス・ファイル、およびアプレットでグローバリゼーション・サポートが必要な場合は、orai18n.jarファイルから要求されたクラス・ファイル

- アプレットのクラス

4. ZIPファイルやJARファイルが圧縮されていないことを確認してください。

これでユーザーがアプレットを使用できるようになります。アプレットを利用するには、アプレットを実行するHTMLページにAPPLETタグを追加する方法があります。たとえば、次のようになります。

<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet ARCHIVE=JdbcApplet.zip
CODEBASE=Applet_Samples
</APPLET>

HTMLページでのアプレットの指定

APPLETタグは、HTMLページのコンテキスト内で実行されるアプレットを指定します。APPLETタグには、CODE、ARCHIVE、CODEBASE、WIDTHおよびHEIGHTの各属性を指定できます。次の各項では、これらの属性について説明します。

- CODE、HEIGHTおよびWIDTH

- CODEBASE

- ARCHIVE

CODE、HEIGHTおよびWIDTH

アプレットを実行するHTMLページには、アプレット表示領域のサイズを指定する初期の幅および高さとともに、APPLETタグが必要です。ピクセル単位のサイズを指定するには、HEIGHTおよびWIDTH属性を使用します。サイズには、アプレットがオープンするウィンドウまたはダイアログ・ボックスのサイズは含めません。

APPLETタグには、アプレットのコンパイル済Appletサブクラスを含むファイルの名前も指定する必要があります。このファイル名はCODEパラメータで指定します。パスはすべてアプレットのベースURLの相対パスにする必要があります。絶対パスは使用できません。

次の例にあるJdbcApplet.classは、コンパイルされたアプレットの名前です。

<APPLET CODE="JdbcApplet" WIDTH=500 HEIGHT=200>
</APPLET>

この形式のCODE属性を使用する場合は、アプレットおよびJDBC ThinドライバのためのクラスがこのHTMLページと同じディレクトリ内にある必要があります。

注意:
CODE属性には、ファイル拡張子.classを含めないでください。

CODEBASE

CODEBASE属性は省略可能です。この属性は、アプレットのベースURL、つまりアプレットのコードがあるディレクトリの名前を指定します。指定しない場合は、ドキュメントのURLが使用されます。つまり、アプレットおよびJDBC Thinドライバのためのクラスが、HTMLページと同じディレクトリ内にある必要があります。たとえば、現行ディレクトリがmy_Dirであるとします。

<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet CODEBASE="."
</APPLET>

属性CODEBASE="."は、このアプレットが現行ディレクトリmy_Dir内にあることを示します。

ここでは、次のようにCODEBASEの値がApplet_Samplesに設定されているとします。

<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet CODEBASE="Applet_Samples"
</APPLET>

これにより、アプレットは、ディレクトリmy_Dir/Applet_Samplesの中にあることになります。

ARCHIVE

ARCHIVE属性は省略可能です。この属性は、アプレットのクラスおよびそのアプレットに必要なリソースが格納されているアーカイブ・ファイルの名前を指定します。サーバーとの余計なラウンドトリップを大幅に削減できるため、アーカイブ・ファイルの使用をお薦めします。

アーカイブ・ファイルはあらかじめロードされます。リストに複数のアーカイブ・ファイルを指定する場合は、カンマで区切ります。次の例にあるクラス・ファイルは、アーカイブ・ファイルJdbcApplet.zipに格納されています。

<APPLET CODE="JdbcApplet" ARCHIVE="JdbcApplet.zip" WIDTH=500 HEIGHT=200>
</APPLET>

注意:
バージョン3.0のブラウザでは、ARCHIVE属性はサポートされていません。

6 JDBC OCIドライバ固有の機能

この章では、Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバ固有の機能について説明します。OCI Instant Clientについても説明します。この章の内容は次のとおりです。

- OCI接続プーリング

- クライアント結果キャッシュ

- 透過的アプリケーション・フェイルオーバー

- OCIネイティブXA

- OCI Instant Client

- Instant Client Light(English)

OCI接続プーリング

OCI接続プーリング機能は、オラクル社設計の拡張機能です。JDBC OCIドライバで提供される接続プーリングによって、アプリケーションは少数の物理接続を使用して、複数の論理接続を保持できます。この論理接続でのコールは、指定された時間に使用可能な物理接続にルーティングされます。

関連項目:
第24章「OCI接続プーリング」

クライアント結果キャッシュ

クライアント結果キャッシュ機能により、クライアント側でのSQL問合せ結果セットのクライアント・メモリーへのキャッシュが可能になります。このようにして、OCIアプリケーションでは、クライアント・メモリーを使用することで、繰返しの問合せのレスポンス時間を改善するためにクライアント結果キャッシュを利用できます。

関連項目:
Oracle Call Interfaceプログラマーズ・ガイド

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

- クライアント結果キャッシュの利点

- JDBCでの使用ガイドライン

クライアント結果キャッシュの利点

OCIクライアント側結果セット・キャッシュには次のような利点があります。

- JDBC OCIクライアント側結果セット・キャッシュは、OCIアプリケーションに対して完全に透過的です。結果セット・データのキャッシュは、結果セットに影響を与えるすべてのセッションまたはデータベース変更と一致するように維持されています。

- 結果セットはクライアント側にあるため、キャッシュ・ヒットが起こると、サーバーへのラウンドトリップが行われるのではなく、SQL問合せが実行され、ローカルに処理するようにフェッチがコールされます。このため、サーバーCPUやサーバーI/Oなどのサーバー・リソースにとって、非常に大きなパフォーマンスの節約になります。

- JDBC OCIクライアント上の結果キャッシュはプロセスごとのものであるため、複数のクライアント・セッションで、キャッシュされた一致している結果セットを同時に使用できます。

- JDBC OCIクライアントの結果キャッシュにより、各OCIアプリケーションが独自のカスタム結果セット・キャッシュを持つ必要性が最小限に抑えられます。

- JDBC OCIクライアントの結果キャッシュではOCIクライアント・メモリーが使用され、サーバー・メモリーよりコストが低くなります。

JDBCでの使用ガイドライン

結果キャッシュを有効化するには次の2つの方法があります。

- RESULT_CACHE_MODEパラメータ

- 表注釈

- SQLヒント

注意:

- JDBC OCIクライアント結果キャッシュを使用する際は、JDBC文キャッシュを使用するか、またはキャッシュ文をアプリケーション・レベルで使用する必要があります。JDBC文キャッシュの詳細は、「文キャッシュと結果セット・キャッシュ」を参照してください。

- SQLヒントは、セッション・パラメータRESULT_CACHE_MODEおよび表注釈よりも優先されます。表注釈FORCEはセッション・パラメータよりも優先されます。

RESULT_CACHE_MODEパラメータ

RESULT_CACHE_MODEパラメータを使用して、問合せで使用する表の結果キャッシュ・モードを決定できます。ALTER SESSIONおよびALTER SYSTEM文でこの句を使用するか、またはサーバー・パラメータ・ファイル(init.ora)内でこの句を使用して、結果キャッシュを決定します。RESULT_CACHE_MODEパラメータを設定して、SQL問合せ結果キャッシュをすべての問合せで使用するか、SQLヒントまたは表注釈を使用して結果キャッシュ・ヒントで注釈を付けられている問合せのみで使用するかを制御できます。

表注釈

表注釈を使用して、コードを変更しないで結果キャッシュを有効にできます。ALTER TABLEおよびCREATE TABLE文を使用すると、結果キャッシュ・モードで表に注釈を付けることができます。構文は次のとおりです。

CREATE|ALTER TABLE [<schema>.]<table> ... [RESULT_CACHE (MODE {FORCE|DEFAULT})]

次の例では、CREATE TABLE文で表注釈を使用する方法を示しています。

CREATE TABLE foo (a NUMBER, b VARCHAR2(20)) RESULT_CACHE (MODE FORCE);

次の例では、ALTER TABLE文で表注釈を使用する方法を示しています。

ALTER TABLE foo RESULT_CACHE (MODE DEFAULT);

SQLヒント

SQLヒントを使用し、/*+ result_cache */または/*+ no_result_cache */のヒントの付いている問合せに注釈を付けることによってキャッシュする問合せを指定できます。たとえば、次のコードを見てください。

String  query  = "select /*+ result_cache */ * from emp where empno < : 1";
((oracle.jdbc.OracleConnection)conn).setImplicitCachingEnabled(true);
((oracle.jdbc.OracleConnection)conn).setStatementCacheSize(10);
PreparedStatement  pstmt;
ResultSet rs;

for (int j = 0 ; j < 10 ; j++ )
{
pstmt  = conn.prepareStatement (query);
pstmt.setInt(1,7500);
rs  = pstmt.executeQuery();
while (rs.next( ) )
{     // see the values  }
rs.close;
pstmt.close( ) ;
}
}

この例では、クライアント結果キャッシュのヒント/*+ result_cache */が、実際の問合せであるselect * from emp where empno < : 1に注釈として付けられています。したがって、問合せは最初にデータベースに対して実行され、その結果セットが、問合せの残り9回の実行用にキャッシュされます。これにより、アプリケーションのパフォーマンスは大幅に向上します。これは主として読取り専用データの場合に便利です。

SQLヒントの例を次に示します。次の例はすべて、dept表が結果キャッシュのために次のコマンドによって注釈を付けられていることを前提にしています。

ALTER TABLE dept result_cache (MODE FORCE);

例

- SELECT * FROM emp
結果セットはキャッシュされません。

- SELECT * FROM dept
結果セットはキャッシュされます。

- SELECT /*+ result_cache */ empno FROM emp
結果セットはキャッシュされます。

- SELECT /*+ no_result_cache */ deptno FROM dept
結果セットはキャッシュされません。

- SELECT /*+ result_cache */ * FROM dept
問合せヒントは不要ですが、結果セットはキャッシュされます。

- SELECT e.ename FROM emp e, dept d WHERE e.deptno = d.deptno
問合せヒントが使用不可で、すべての表がFORCEとして注釈を付けられていないため、結果セットはキャッシュされません。

注意:
使用ガイドライン、クライアント・キャッシュの整合性、デプロイ時間の設定、クライアント・キャッシュ統計情報、クライアント結果キャッシュの検証およびOCIクライアント結果キャッシュとサーバー結果キャッシュの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

透過的アプリケーション・フェイルオーバー

JDBC OCIドライバの透過的アプリケーション・フェイルオーバー機能を使用すると、接続先のデータベース・インスタンスがダウンした場合でも、データベースに自動的に再接続できます。別のノードで作成されても、新しいデータベース接続は元の接続とまったく同じです。

関連項目:
第28章「透過的アプリケーション・フェイルオーバー」

OCIネイティブXA

JDBC OCIには、ネイティブXAと呼ばれる機能も用意されています。この機能により、ネイティブAPIを使用してXAコマンドを送信できます。非ネイティブAPIと比較して、ネイティブAPIを使用するほうが、高いパフォーマンスを達成できます。

関連項目:
「OCIネイティブXA」

OCI Instant Client

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

- Instant Clientの概要

- Instant Clientの利点

- JDBC OCI Instant Clientのインストール手順

- Instant Clientの使用

- Instant Client共有ライブラリのパッチ

- データ共有ライブラリとZIPファイルの再生成

- OCI Instant Client用のデータベース接続名

- OCI Instant Clientの環境変数

Instant Clientの概要

Instant Client機能を使用すると、Oracleホームの必要性がなくなり、OCI、Oracle C++ Call Interface(OCCI)、Open Database Connectivity(ODBC)およびJDBC-OCIベースのカスタマ・アプリケーションのデプロイが非常に簡単になります。Instant Clientモードで実行するJDBC OCIアプリケーションに必要な記憶域の容量は、クライアント側に完全にインストールして実行するアプリケーションに比べて少なくなります。Instant Clientの共有ライブラリに使用されるディスク領域は、クライアント側に完全にインストールした場合の約1/4です。

表6-1は、JDBC OCIアプリケーションのデプロイに必要なOracleのクライアント側ファイルを示しています。この表では、リリース11.2のライブラリ名を使用しています。ライブラリ名の数字の部分は、リリースに応じて将来変更されます。

表6-1 OCI Instant Client共有ライブラリ

LinuxシステムとUNIXシステム

LinuxシステムとUNIXシステムの場合の説明

Microsoft Windows

Microsoft Windowsの場合の説明

libclntsh.so.11.2

クライアント・コード・ライブラリ

oci.dll

アプリケーションがリンクする各機能の転送

libociei.so

OCI Instant Clientデータ共有ライブラリ

oraociei11.dll

データとコード

libnnz11.so

セキュリティ・ライブラリ

orannzsbb11.dll

セキュリティ・ライブラリ

libocijdbc11.so

OCI Instant Client JDBCライブラリ

ocijdbc11.dll

OCI Instant Client JDBCライブラリ

すべてのJDBC Javaアーカイブ(JAR)ファイル

関連項目: 「環境変数の確認」

すべてのJDBC JARファイル

関連項目: 「環境変数の確認」

注意:
ネイティブXA機能を提供するには、JDBC XAクラス・ライブラリをコピーする必要があります。UNIXシステムでは、このライブラリlibheteroxa11.soはORACLE_HOME/jdbc/libディレクトリに格納されています。Microsoft Windowsでは、このライブラリheteroxa11.dllはORACLE_HOME\binディレクトリに格納されています。

Instant Clientの利点

Instant Clientには次のような利点があります。

- インストール時にコピーされるファイルの数がそれほど多くありません。

- Oracleのクライアント側で必要なファイルの数と合計ディスク領域が大幅に減少します。

- Instant Clientでデプロイされたアプリケーションでは、機能またはパフォーマンスに損失がありません。

- サード・パーティのソフトウェア・ベンダーがアプリケーションを簡単にパッケージ化できます。

JDBC OCI Instant Clientのインストール手順

Instant Clientライブラリは、Oracle Universal InstallerでInstant Clientオプションを選択するとインストールできます。Oracle Technology NetworkのWebサイトからダウンロードすることもできます。インストールの手順は、次のとおりです。

1. Instant Client共有ライブラリおよびOracle JDBCクラス・ライブラリをダウンロードし、instantclientなどのディレクトリにインストールします。

2. ライブラリ・パスの環境変数を、手順1のディレクトリに設定します。たとえば、UNIXシステムでは、LD_LIBRARY_PATH環境変数をinstantclientに設定します。Microsoft Windowsでは、PATH環境変数をinstantclientディレクトリに設定します。

3. CLASSPATH環境変数に、JDBCクラス・ライブラリの完全パス名を追加します。

これで、JDBC OCIアプリケーションを実行する準備が整いました。

JDBC OCIアプリケーションは、ライブラリ・パスの環境変数を介してOCI共有ライブラリおよびJDBC共有ライブラリにアクセスできる場合、Instant Clientモードで動作します。Instant ClientモードではORACLE_HOMEへの依存性はなく、ORACLE_HOMEに用意されている他のコードおよびデータファイルは、tnsnames.oraファイルを除いて、JDBC OCIには不要です。

Instant Clientは、Oracle Universal InstallerでInstant Clientオプションを選択するとインストールできます。Instant Clientファイルは、必ず空のディレクトリにインストールしてください。Instant Clientモードで動作するには、OTNのインストールと同じように、LD_LIBRARY_PATH環境変数をInstant Clientディレクトリに設定する必要があります。

管理者オプションを選択して完全なクライアント・インストールを実行した場合は、Instant Client共有ライブラリもインストールされます。完全なクライアント・インストールでは、Instant Client共有ライブラリおよびJDBCクラスは次の場所に格納されます。

LinuxシステムまたはUNIXシステムの場合:

- libociei.soライブラリは、$ORACLE_HOME/instantclientに格納されます。

- libclnstsh.so.11.2、libocijdbc11.soおよびlibnnz11.soは、$ORACLE_HOME/libに格納されます。

- JDBCクラス・ライブラリは、$ORACLE_HOME/jdbc/libに格納されます。

Microsoft Windowsの場合:

- oraociei11.dllライブラリはORACLE_HOME\instantclientに格納されます。

- oci.dll、ocijdbc11.dllおよびorannzsbb11.dllは、ORACLE_HOME\binに格納されます。

- JDBCクラス・ライブラリはORACLE_HOME\jdbc\libに格納されます。

これらのファイルを別のディレクトリにコピーし、そのディレクトリにライブラリ・パスを設定し、JDBCクラス・ライブラリのパス名をCLASSPATH環境変数に追加すると、JDBC OCIアプリケーションをInstant Clientモードで実行できます。

注意:

- ネイティブXA機能を提供するには、JDBC XAクラス・ライブラリをコピーする必要があります。UNIXでは、このライブラリlibheteroxa11.soはORACLE_HOME/jdbc/libに格納されています。Windowsでは、このライブラリheteroxa11.dllはORACLE_HOME\binに格納されています。

- すべてのライブラリは、同じORACLE_HOMEからコピーし、同じディレクトリに格納する必要があります。

- Instant Clientモードで操作するJDBC OCIドライバが、Sparc64などのハイブリッド・プラットフォームで必要な場合は、ORACLE_HOME/instantclient32ディレクトリからlibociei.soライブラリをコピーする必要があります。JDBC OCI Instant Clientに必要なその他すべてのSparc64ライブラリは、ORACLE_HOME/lib32ディレクトリからコピーしてください。

- ライブラリ・パス環境変数で、Oracleライブラリのセットを1つのみ指定する必要があります。つまり、複数のディレクトリにInstant Clientライブラリが含まれている場合、ライブラリ・パス環境変数で、該当するディレクトリを1つのみ指定します。

- コンピュータ上でOracleホームを使用している場合、ライブラリ・パス環境変数での指定順序に関係なく、ライブラリ・パス環境変数でORACLE_HOME/libとInstant Clientディレクトリを同時に使用しないでください。つまり、ライブラリ・パス環境変数で、ORACLE_HOME/libディレクトリ(Instant Client以外で動作している場合)またはInstant Clientディレクトリ(Instant Clientで動作している場合)のいずれか一方のみを指定します。

- Instant Clientは、Oracle Technology Network(OTN)からダウンロードすることをお薦めします。
http://www.oracle.com/technology/tech/oci/instantclient/instantclient.html

Instant Clientの使用

Instant Clientはデプロイメント用の機能であるため、本番アプリケーションの実行に使用します。デプロイメントでは、デモ用のプログラムなどにアクセスできるようにするために、完全インストールが必要です。一般的に、Instant Clientモードがクライアント側動作専用でないかぎり、Instant Clientモードで実行されているアプリケーションではすべてのJDBC OCI機能を使用できます。したがって、サーバー側の外部プロシージャは、Instant Clientモードでは動作しません。

Instant Client共有ライブラリのパッチ

Instant Clientはデプロイメント用の機能であるため、JDBC OCIアプリケーションの実行に必要なファイルの数とサイズの減少に重点が置かれています。したがって、Instant Client共有ライブラリのパッチに必要なすべてのファイルがInstant Clientのデプロイ時に揃っているわけではありません。Instant Client共有ライブラリのパッチには、ORACLE_HOMEベースの完全クライアント・インストールが必要です。opatchユーティリティを使用して、Instant Client共有ライブラリにパッチを適用します。

注意:
Microsoft Windows上では、共有ライブラリにパッチを当てることはできません。

ORACLE_HOME環境でパッチを適用した後、表6-1「OCI Instant Client共有ライブラリ」のファイルをInstant Clientディレクトリにコピーします。「JDBC OCI Instant Clientのインストール手順」を参照してください。

個々のファイルをコピーするかわりに、「データ共有ライブラリとZIPファイルの再生成」の説明に従って、OCI、OCCI、JDBCおよびSQL*Plus用のInstant Client ZIPファイルを生成できます。次に、「JDBC OCI Instant Clientのインストール・プロセス」に従って、ZIPファイルをターゲット・コンピュータにコピーして解凍できます。

opatchユーティリティは、libclnstsh.so.11.2にORACLE_HOMEインストールのパッチ情報を格納します。次のコマンドを使用すると、この情報を取り出すことができます。

genezi -v

Instant Clientのデプロイ元のコンピュータにgeneziユーティリティが装備されていない場合、ORACLE_HOMEインストールが装備されたコンピュータ上のORACLE_HOME/binディレクトリからコピーする必要があります。

データ共有ライブラリとZIPファイルの再生成

ORACLE_HOMEを管理者オプションでインストールした場合は、次の手順を実行して、OCI Instant Clientデータ共有ライブラリ(libociei.so)を再生成できます。

mkdir -p $ORACLE_HOME/rdbms/install/instantclient/light
cd $ORACLE_HOME/rdbms/lib
make -f ins_rdbms.mk ilibociei

ORACLE_HOME内の現行ファイルに基づく新しいバージョンのlibociei.soデータ共有ライブラリが、ORACLE_HOME/rdbms/install/instantclientディレクトリに配置されます。

再生成されるデータ共有ライブラリ(libociei.so)の場所は、元のデータ共有ライブラリ(libociei.so)の場所と異なり、ORACLE_HOME/instantclientディレクトリですので注意してください。前の手順では、OCI、OCCI、JDBCおよびSQL*PlusのInstant Client ZIPファイルも生成されます。

Microsoft Windowsプラットフォームでは、データ共有ライブラリとZIPファイルを再生成することはできません。

OCI Instant Client用のデータベース接続名

tnsnames.oraやsqlnet.oraなどの構成ファイルの格納先としてORACLE_HOMEまたはTNS_ADMIN環境変数を使用しないOracle Netネーミング・メソッドは、すべてInstant Clientモードで動作します。特に、接続文字列は次のような形式で指定できます。

- 次のようなThin形式の接続文字列の場合:

host:port:service_name

たとえば、次のようになります。

url="jdbc:oracle:oci:@//example.com:5521:bjava21"

- 次のようなSQL接続URL文字列の場合:

//host:[port][/service name]

たとえば、次のようになります。

url="jdbc:oracle:oci:@//example.com:5521/bjava21

- Oracle Netのキーワード値ペア。たとえば、次のようになります。

url="jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)
(HOST=dlsun242) (PORT=5521))
(CONNECT_DATA=(SERVICE_NAME=bjava21)))"

構成ファイルの格納先としてTNS_ADMINが必要なネーミング・メソッドをそのまま使用するには、TNS_ADMIN環境変数を設定します。

関連項目:
接続フォーマットの詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。

TNS_ADMIN環境変数を設定せずに、inst1などのTNSNAMESエントリを使用する場合は、ORACLE_HOME環境変数を設定し、構成ファイルを$ORACLE_HOME/network/adminディレクトリに格納する必要があります。

注意:
この場合、ORACLE_HOME環境変数は、Oracle Net構成ファイルの格納先としてのみ使用されます。それ以外のクライアント・コード・ライブラリのコンポーネントでは、ORACLE_HOME環境変数の値は使用されません。

空の接続文字列は、サポートされません。ただし、空の接続文字列の使用に代わる方法として、tnsnames.oraエントリまたはOracle Netキーワード値ペアに対して、UNIXシステム上ではTWO_TASK環境変数を、Microsoft Windows上ではLOCAL変数を設定する方法があります。TWO_TASKまたはLOCALがtnsnames.oraエントリに設定されている場合、TNS_ADMINまたはORACLE_HOME設定によってtnsnames.oraファイルをロードする必要があります。

例

データベース・サーバー上のlistener.oraファイルに次の情報が格納されているとします。

LISTENER = (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=server6)(PORT=1573)))

SID_LIST_LISTENER = (SID_LIST=
(SID_DESC=(SID_NAME=rdbms3)
(GLOBAL_DBNAME=rdbms3.server6.us.alchemy.com)
(ORACLE_HOME=/home/dba/rdbms3/oracle)))

このサーバーには、次のいずれかの方法で接続できます。

url = "jdbc:oracle:oci:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)
(HOST=server6)(PORT=1573))
(CONNECT_DATA=(SERVICE_NAME=rdbms3.server6.us.alchemy.com)))"

または

url = "jdbc:oracle:oci:@//server6:1573/rdbms3.server6.us.alchemy.com"

または、TWO_TASK環境変数を任意の接続文字列に設定すれば、sqlplusコマンドとともに接続文字列を指定しなくても、データベース・サーバーに接続できます。たとえば、次の方法のいずれかを使用してTWO_TASK環境変数を設定します。

setenv TWO_TASK "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=server6)(PORT=1573))
(CONNECT_DATA=(SERVICE_NAME=rdbms3.server6.us.alchemy.com)))"

または

setenv TWO_TASK //server6:1573/rdbms3.server6.us.alchemy.com

これで、次のURLを使用すると、データベース・サーバーに接続できます。

url = "jdbc:oracle:oci:@"

接続文字列は、tnsnames.oraファイルに格納できます。たとえば、tnsnames.oraファイルに次の情報が格納されているとします。

conn_str = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=server6)(PORT=1573))
(CONNECT_DATA=(SERVICE_NAME=rdbms3.server6.us.alchemy.com)))

このtnsnames.oraファイルが/home/webuser/instantclientディレクトリに配置されている場合、次のように、TNS_ADMIN環境変数(または、Microsoft WindowsではLOCAL)を設定できます。

setenv TNS_ADMIN /home/webuser/instantclient

これで、次のように接続できます。

url = "jdbc:oracle:oci:@conn_str"

注意:
TNS_ADMIN環境変数では、tnsnames.oraファイルが配置されているディレクトリを指定します。ただし、TNS_ADMINでは、tnsnames.oraファイルのフルパスを指定するのではなく、ディレクトリを指定します。

このtnsnames.oraファイルが、Oracleホームの/network/server6/home/dba/oracle/network/adminディレクトリに配置されている場合、TNS_ADMINを使用してtnsnames.oraファイルを配置するかわりに、次のようにORACLE_HOME環境変数を使用できます。

setenv ORACLE_HOME /network/server6/home/dba/oracle

これで、先に指定したように、接続文字列conn_strのいずれかを使用して接続できます。

TNS_ADMINまたはORACLE_HOMEによってtnsnames.oraを特定できる場合、TWO_TASKは次のように設定できます。

setenv TWO_TASK conn_str

次のURLで接続できます。

url = "jdbc:oracle:oci:@"

OCI Instant Clientの環境変数

ORACLE_HOME環境変数は、NLS、COREおよびエラー・メッセージ・ファイルの位置を決定するものではなくなりました。OCIのみのアプリケーションでは、ORACLE_HOME環境変数を設定する必要はありません。ただし、変数が設定されていても、OCIドライバの動作に影響はありません。OCIドライバは、常にデータ共有ライブラリからドライバのデータを入手します。データ共有ライブラリが利用できない場合のみ、ORACLE_HOME環境変数が使用され、フル・クライアント・インストールとみなされます。ORACLE_HOME環境変数は設定不要ですが、設定する場合は、ディレクトリを識別する有効なオペレーティング・システム・パス名に設定する必要があります。

Instant Clientモードの場合、環境変数ORA_NLS10およびORA_NLSPROFILES33は無視されます。

Instant Clientモードでは、ORA_TZFILE変数を使用しない場合、サイズの大きいデフォルトのtimezlrg_n.datファイルがデータ共有ライブラリから使用されます。サイズの小さいtimezone_n.datファイルをデータ共有ライブラリから使用する場合は、絶対または相対パス名を付けずに、このファイルの名前をORA_TZFILE環境変数に設定します。つまり、次のように設定します。

UNIXシステムの場合:

setenv ORA_TZFILE timezone_n.dat

Microsoft Windowsの場合:

set ORA_TZFILE timezone_n.dat

前述の例では、nはタイムゾーン・データファイルのバージョン番号です。

OCIドライバがデータ共有ライブラリを利用できないためにInstant Clientモードで動作しない場合、ORA_TZFILE変数を設定する際は、以前のOracle Databaseのリリースのときと同様に完全パス名を指定します。

TNSNAMESのエントリを使用する場合は、前述のように、TNS_ADMINディレクトリにTNSNAMES構成ファイルを格納する必要があります。TNS_ADMINを設定しない場合は、ORACLE_HOME/network/adminディレクトリにOracle Net Services構成ファイルを格納する必要があります。

Instant Client Light(English)

Instant Clientの軽量バージョンは、Instant Client Light(English)と呼ばれます。Instant Client Lightは、短いファイル名です。Instant Client Lightは、Instant Clientを大幅に小さくしたバージョンです。クライアント・インストールのディスク空き容量要件は、約63MB少なくてすみます。これは、サイズが4MBの軽量データ共有ライブラリ(UNIXシステムの場合libociicus.so)によるもので、これはサイズが67MBのデータ共有ライブラリlibociei.soのサブセットです。

この軽量データ共有ライブラリは、少数のキャラクタ・セットとエラー・メッセージを英語のみでサポートしています。そのため、Instant Client Light(English)という名前が付いています。Instant Client Lightは、英語のエラー・メッセージのみを必要とし、US7ASCIIかWE8DEC、またはUnicodeキャラクタ・セットの1つを使用するアプリケーションに対応して設計されています。

表6-2では、様々なプラットフォームにおけるInstant ClientとInstant Client Light(English)用のデータ共有ライブラリ名を示しています。この表では、各データ共有ライブラリのサイズもライブラリ・ファイル名に続くカッコ内に記載しています。

表6-2 Instant ClientとInstant Client Light(English)用のデータ共有ライブラリ

プラットフォーム

Instant Client

Instant Client Light(English)

Sun Solaris

libociei.so(67MB)

libociicus.so(4MB)

Linux

libociei.so(67MB)

libociicus.so(4MB)

Microsoft Windows

oraociei11.dll(85MB)

oraociicus11.dll(15 MB)

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

- グローバリゼーション設定

- 動作

- インストール

グローバリゼーション設定

NLS_LANG設定は、言語、地域およびキャラクタ・セットを、language_territory.charactersetとして指定します。Instant Client Lightでは、languageはAmericanのみ、territoryはサポートされる任意の値、charactersetは次のいずれかです。

- シングルバイト

- US7ASCII

- WE8DEC

- WE8MSWIN1252

- WE8ISO8859P1

- Unicode

- UTF8

- AL16UTF16

- AL32UTF8

クライアントやサーバーのキャラクタ・セットとしてあげられている以外のキャラクタ・セットまたは各国語キャラクタ・セットを指定したり、クライアントのNLS_LANGに言語を設定したりすると、次のエラーが発生します。

- ORA-12734

- ORA-12735

- ORA-12736

- ORA-12737

Instant Client Lightでは、エラー・メッセージは英語でのみ出力されます。したがって、NLS_LANG設定に有効な値は、次のようになります。

American_territory.characterset

territoryにはサポートされる有効な地域を、charactersetには前述のいずれかのキャラクタ・セットを指定できます。

Instant Client Lightは、OCI_UTF16モードで作成されたOCI環境ハンドルを使用して動作します。

関連項目:
NLS設定の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

動作

Instant Client Lightモードで動作するには、アプリケーションで、UNIXシステムの場合はLD_LIBARARY_PATH環境変数を、Microsoft Windowsの場合はPATH環境変数を、クライアントおよびデータ共有ライブラリが格納されている場所に設定する必要があります。OCIアプリケーションは、デフォルトでOCIデータ共有ライブラリ、つまりUNIXシステムではLD_LIBRARY_PATH環境変数のlibociei.so、Microsoft WindowsではPATH環境変数のoraociei11.dllデータ共有ライブラリを検索して、アプリケーションがInstant Clientモードで動作するかどうかを判断します。このライブラリが見つからない場合、OCIは、Instant Client Lightのデータ共有ライブラリ、つまりUNIXシステムではlibociicus.so、Microsoft Windowsではlibociicus11.dllをロードしようとします。このライブラリが見つかった場合、アプリケーションはInstant Client Lightモードで動作します。このライブラリが見つからない場合は、Instant Client以外のモードとなります。

インストール

Instant Client Lightは、次のいずれかの方法でインストールできます。

- OTNから
次のサイトから必要なファイルをダウンロードできます。

http://www.oracle.com/technology/tech/oci/instantclient/instantclient.html

Instant Client Lightの場合は、Basicパッケージをダウンロードして展開するかわりに、Basic Lightパッケージをダウンロードして解凍します。解凍する前に、軽量ライブラリを解凍するinstantclient_11_2ディレクトリを空にしてください。

- Client Admin Installから
libociei.soまたはoraociei11.dllをORACLE_HOME/instantclientディレクトリからコピーするかわりに、libociicus.soまたはoraociic10.dllをORACLE_HOME/instantclient/lightディレクトリからコピーします。つまり、UNIXシステムの場合、LD_LIBRARY_PATH環境変数のInstant Clientディレクトリに、大規模なOCI Instant Clientのデータ共有ライブラリlibociei.soではなく、Instant Client Lightのデータ共有ライブラリlibociicus.soを格納してください。Microsoft Windowsの場合、PATH環境変数にはoraociei11.dllではなくoraociei11.dllを指定する必要があります。

- Oracle Universal Installerから
Oracle Universal InstallerでInstant Clientオプションを選択すると、libociei.so(Microsoft Windowsの場合はoraociei11.dll)が、インストールのベース・ディレクトリにインストールされ、LD_LIBRARY_PATH環境変数には、このディレクトリが指定されます。このため、Instant Client Lightはデフォルトでは使用できません。Instant Client Lightのデータ共有ライブラリlibociicus.so(Microsoft Windowsの場合はoraociicus11.dll)は、ベース・ディレクトリのlightサブディレクトリにインストールされます。したがって、Instant Client Lightモードで動作するには、OCIデータ共有ライブラリlibociei.so(Windowsではoraociei11.dll)を削除するか、名前を変更し、Instant Client Lightのデータ共有ライブラリを、インストールのlightサブディレクトリからベース・ディレクトリにコピーする必要があります。

たとえば、Oracle Universal Installerで、Instant ClientをLD_LIBRARY_PATH環境変数のmy_oraic_11_1ディレクトリにインストールした場合、Instant Client Lightモードで動作するには、次のようにします。

cd my_oraic_11_1
rm libociei.so
mv light/libociicus.so .

注意:
Instant Clientファイルは、必ず空のディレクトリにコピーまたはインストールしてください。これは、インストール時に互換性のないバイナリが存在しないようにするためです。

7 サーバー側内部ドライバ

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

- サーバー側内部ドライバの概要

- データベースへの接続

- セッション・コンテキストおよびトランザクション・コンテキスト

- サーバー上でのJDBCのテスト

- サーバーへのアプリケーションのロード

サーバー側内部ドライバの概要

サーバー側内部ドライバは、Oracle DatabaseとOracle Java仮想マシン(Oracle JVM)に結び付けられています。このドライバは、データベースと同じプロセスの一部として動作します。また、デフォルトのセッション(Oracle JVMが起動されたセッションと同じセッション)内で動作します。各Oracle JVMセッションには、存在するデータベース・セッションに対して1つの暗黙的なネイティブ接続があります。この接続は概念的で、Javaオブジェクトではありません。これはこのセッションに固有な側面であり、JVM内でオープンまたはクローズできません。

サーバー側内部ドライバはデータベース・サーバー内で動作するよう最適化されており、このドライバを使用するとローカル・データベース上のSQLデータおよびPL/SQLサブプログラムに直接アクセスできます。JVM全体は、データベースおよびSQLエンジンと同じアドレス空間内で動作します。SQLエンジンへのアクセスはファンクション・コールです。これによって、Java Database Connectivity(JDBC)アプリケーションのパフォーマンスが向上し、SQLエンジンへのアクセスにリモートOracle Netコールを実行するよりも速くなります。

サーバー側内部ドライバは、クライアント側ドライバと同じ機能、Application Program Interface(API)およびOracle拡張機能をサポートします。これにより、アプリケーションのパーティション化が非常に簡単になります。たとえば、データ集中処理型のJavaアプリケーションがある場合は、アプリケーション固有のコールを修正しなくても、パフォーマンスを向上させるために簡単にデータベース・サーバーに移動できます。

データベースへの接続

前の項で説明したように、サーバー側内部ドライバはデフォルトのセッション内で動作します。したがって、すでに接続された状態になっています。デフォルト接続にアクセスするには、次の2つのメソッドを使用できます。

- 次のいずれかの形式をURL文字列として、OracleDataSource.getConnectionメソッドを使用します。

- jdbc:oracle:kprb

- jdbc:default:connection

- jdbc:oracle:kprb:

- jdbc:default:connection:

- OracleDriverクラスのOracle固有のdefaultConnectionメソッドを使用します。

通常はdefaultConnectionの使用をお薦めします。

注意:
サーバー側内部ドライバと接続するためにOracleDriverクラスを登録する必要はなくなりました。

OracleDriverクラスのdefaultConnectionメソッドによる接続

oracle.jdbc.OracleDriverクラスのdefaultConnectionメソッドは、Oracle拡張機能で、常に同じ接続オブジェクトを戻します。発生した接続オブジェクトを別の変数名に割り当て、このメソッドを複数回コールしたとしても、1つの接続オブジェクトのみが再利用されます。

defaultConnectionコールに接続文字列を含める必要はありません。たとえば、次のようになります。

import java.sql.*;
import oracle.jdbc.*;

class JDBCConnection
{
public static Connection connect() throws SQLException
{
Connection conn = null;
try {
// connect with the server-side internal driver
conn = ora.defaultConnection();
}

} catch (SQLException e) {...}
return conn;
}
}

この例にはconn.closeコールがないことに注意してください。JDBCコードがターゲット・サーバー内で実行されている場合、接続は暗黙的なデータ・チャネルで、クライアントからの場合のように明示的な接続インスタンスではありません。クローズしないでください。

OracleDriverは、デフォルトの接続インスタンスを格納するための静的な値です。接続が存在しクローズされていない場合に、メソッドOracleDriver.defaultConnectionはこのデフォルトの接続インスタンスを戻します。それ以外の場合、新しいオープン・インスタンスを作成し、静的な値に格納してコール元に戻します。

通常、OracleDriver.defaultConnectionメソッドを使用します。このメソッドは、高速でリソースをあまり使用しません。Javaストアド・プロシージャは注意深く記述する必要があります。たとえば、各コールを終了する前に文をクローズします。

通常、デフォルトの接続インスタンスはクローズしないでください。このインスタンスは複数の場所に格納される可能性がある単一インスタンスであり、クローズするとそれぞれの場所が使用できなくなります。クローズすると、それ以降にOracleDriver.defaultConnectionメソッドをコールしたときに、新しいオープン・インスタンスが作成されます。

OracleDataSource.getConnectionメソッドによる接続

ターゲット・サーバー内で実行中のコードから内部サーバー接続に接続するには、次のいずれかのURLとともに、OracleDataSource.getConnectionメソッドを使用できます。

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:kprb");
Connection conn = ods.getConnection();

または

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:default:connection");
Connection conn = ods.getConnection();

または

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:kprb:");
Connection conn = ods.getConnection();

または

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:default:connection:");
Connection conn = ods.getConnection();

URL内で指定したユーザー名またはパスワードは、デフォルトのサーバー接続への接続では無視されます。

OracleDataSource.getConnectionメソッドをコールするたびに、このメソッドは新しいJava Connectionオブジェクトを戻します。オブジェクト・マップまたは型マップを操作している場合は、OracleDataSource.getConnectionをコールするたびに、このメソッドが新しい接続オブジェクトを戻すということに重要な意味があります。型マップは、特定のConnectionオブジェクトおよびそのオブジェクトの一部である状態に関連付けられます。プログラムの一部として複数の型マップを使用する場合は、getConnectionをコールして、各型マップに対して新しいConnectionオブジェクトを作成できます。

注意:
OracleDataSource.getConnectionメソッドはコールするたびに新規オブジェクトを戻しますが、毎回、新しいデータベース接続を作成するわけではありません。同じ暗黙的なネイティブ接続を使用し、同じセッション状態(特にローカル・トランザクション)を共有します。

セッション・コンテキストおよびトランザクション・コンテキスト

サーバー側ドライバは、デフォルト・セッションおよびデフォルト・トランザクションのコンテキストで動作します。デフォルト・セッションとは、JVMが起動されたセッションです。サーバー上では、事実上データベースにすでに接続されています。これは、デフォルト・セッションがないクライアント側とは異なります。クライアント側では、明示的にデータベースに接続する必要があります。

サーバーでは、自動コミット・モードは無効になっています。接続オブジェクトで適切なメソッドを使用して、明示的にトランザクションのCOMMITおよびROLLBACK操作を管理する必要があります。

conn.commit();

または

conn.rollback();

注意:
ベスト・プラクティスとして、サーバー内ではトランザクションをコミットまたはロールバックしないことをお薦めします。

サーバー上でのJDBCのテスト

クライアント上で実行できるJDBCプログラムはほとんどすべてサーバー上でも実行できます。samplesディレクトリ内のすべてのプログラムは、少し修正するのみでサーバー上で実行できます。通常、修正は接続文に関するもののみです。

データベースへの接続を取得するための次のようなコード・フラグメントについて考えてみます。

ods.setUrl(
"jdbc:oracle:oci:@(DESCRIPTION=
(ADDRESS=(PROTOCOL=TCP)(HOST=cluster_alias)
(PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=service_name)))");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

サーバー側内部ドライバで使用できるように、このコード・フラグメントを変更できます。サーバー側内部ドライバでは、ユーザー、パスワードまたはデータベースの情報は不要です。接続文は次のように記述します。

ods.setUrl(
"jdbc:oracle:kprb:@");
Connection conn = ods.getConnection();

ただし、接続を取得するには、次のようにOracleDriver.defaultConnectionメソッドをコールするのが最も便利な方法です。

Connection conn = OracleDriver.defaultConnection();

サーバーへのアプリケーションのロード

サーバーにアプリケーションをロードする場合は、クライアントでコンパイル済の.classファイルをロードするか、.javaソース・ファイルをロードして、サーバーで自動的にコンパイルできます。

loadjavaユーティリティの使用

loadjavaユーティリティを使用してファイルをロードします。コマンドラインでソース・ファイル名を指定するか、Javaアーカイブ(JAR)ファイルにそのファイルを格納して、コマンドラインでそのJARファイル名を指定します。

実際のユーティリティを実行するloadjavaスクリプトは、Oracleホームのbinディレクトリにあります。このディレクトリは、Oracleをインストールしたパスにあります。

注意:
loadjavaユーティリティは圧縮ファイルをサポートしています。

サーバーへのクラス・ファイルのロード

アプリケーションに3つのクラス・ファイルFoo1.class、Foo2.classおよびFoo3.classがある場合を考えてみます。各クラスは、サーバーで独自のクラス・スキーマ・オブジェクトに書き込まれます。

次のように、JDBC Oracle Call Interface(OCI)のデフォルト・ドライバを使用して、クラス・ファイルをロードできます。

- クラス・ファイル名を個別に指定します。

loadjava -user scott Foo1.class Foo2.class Foo3.class
Password: password

- ワイルドカードを使用してクラス・ファイル名を指定します。

loadjava -user scott Foo*.class
Password: password

- クラス・ファイルが格納されているJARファイルを指定します。

loadjava -user scott Foo.jar
Password: password

次のように、JDBC Thinドライバを使用してファイルをロードできます。

loadjava -thin -user scott@localhost:1521:ORCL Foo.jar
Password: password

注意:
サーバー側埋込みJVMは、Java Development Kit(JDK)1.5を使用しているため、サーバーにロードする場合は、JDK 1.5でクラスをコンパイルすることをお薦めします。これによって、実行時ではなく、コンパイル時に非互換性が捕捉されます。

サーバーへのソース・ファイルのロード

.javaソース・ファイルをロードする際にloadjava -resolveオプションを有効にすると、サーバー側コンパイラはロード時にアプリケーションをコンパイルします。その結果、オリジナル・ソース・コードのソース・スキーマ・オブジェクトとコンパイル済出力の1つ以上のクラス・スキーマ・オブジェクトの両方が生成されます。

-resolveを指定しない場合は、ソースはコンパイルされずに、ソース・スキーマ・オブジェクトにロードされます。ただし、この場合は、ソースで定義されたクラスを最初に使用しようとしたときに、ソースが暗黙的にコンパイルされます。

たとえば、デフォルトのJDBC OCIドライバを使用して、Foo.javaをロードしてコンパイルするには、次のようにloadjavaを実行します。

loadjava -user scott -resolve Foo.java
Password: password

あるいは、次のコマンドを入力し、JDBC Thinドライバを使用してロードします。

loadjava -thin -user scott@localhost:1521:ORCL -resolve Foo.java
Password: password

どちらの場合にも、ソース・スキーマ・オブジェクトに加えて、適切なクラス・スキーマ・オブジェクトが作成されます。

注意:
通常はできるかぎりクライアントでソースをコンパイルし、ソース・ファイルではなく、.classファイルをサーバーにロードすることをお薦めします。

関連項目:
『Oracle Database Java開発者ガイド』

JVMコマンドラインの使用

JVMコマンドライン・オプションを使用してファイルをロードすることもできます。Oracle JVMに対するコマンドライン・インタフェースは、JDKまたはJREのシェル・コマンドの使用方法と似ています。次のことが可能です。

- 標準の-classpath構文を使用して、ロードするクラスの検索場所を示します。

- 標準の-D構文を使用して、システム・プロパティを設定します。

このインタフェースは、文字列(VARCHAR2)引数を取り、この引数をコマンドライン入力として解析するPL/SQLファンクションです。形式が適切であれば、Oracle JVMで指定のJavaメソッドを実行します。これを実行するために、PL/SQLのパッケージDBMS_JAVAには次のファンクションが用意されています。

- runjava
runjavaファンクションを使用するには、次のようにします。

FUNCTION runjava(cmdline VARCHAR2) RETURN VARCHAR2;

- runjava_in_current_session
runjava_in_current_sessionファンクションを使用するには、次のようにします。

FUNCTION runjava_in_current_session(cmdline VARCHAR2) RETURN VARCHAR2;

注意:
Oracle 11gリリース1(11.1)以降には、Oracle JVM環境用のJust-In-Time(JIT)コンパイラがあります。Oracle JVMのJITコンパイラでは、以前のネイティブ・コンパイラと比較して高度な技術を使用し、動的に生成されたコードをコンパイルするため、実行速度が上がります。以前のネイティブ・コンパイラと異なり、JITコンパイラにはCコンパイラが必要ありません。プラグインのサポートがなくても有効です。
詳細は、『Oracle Database Java開発者ガイド』を参照してください。

第III部

接続とセキュリティ

第III部では、データソースおよびURLを使用したデータベースへの接続について説明します。Oracle Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバとThinドライバでサポートされているセキュリティ機能、JDBC ThinドライバでのSecure Sockets Layer(SSL)サポート、プロキシ接続を介した中間層認証についても説明します。

第III部の構成は次のとおりです。

- 第8章「データソースおよびURL」

- 第9章「JDBCクライアント側セキュリティ機能」

- 第10章「プロキシ認証」

8 データソースおよびURL

この章では、Java Database Connectivity(JDBC)データソースを使用したアプリケーションのデータベースへの接続と、データベースを記述するURLについて説明します。この章の内容は次のとおりです。

- データソース

- データベースURLとデータベース指定子

データソース

データソースは、使用するデータベースまたはその他のリソースを指定するための標準汎用オブジェクトです。データソースの概念は、JDBC 2.0 Extension Application Program Interface(API)で導入されました。データソースは、便宜性と移植性のために、Java Naming and Directory Interface(JNDI)の実体にバインドできるため、データベースには論理名でアクセスできます。

データソース機能は、以前のJDBC DriverManager機能の完全な代替機能を提供します。いずれの機能も同じアプリケーションで使用できますが、使用しているアプリケーションはデータソースに移行することをお薦めします。

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

- JNDIのOracleデータソース・サポートの概要

- データソースの機能とプロパティ

- データソース・インスタンスの作成と接続

- データソース・インスタンスの作成、JNDIへの登録および接続

- サポートされている接続プロパティ

- SYSログインのためのロールの使用方法

- データベース・リモート・ログインの構成

- Bequeathed接続とSYSログオン

- Oracleパフォーマンス拡張要素のプロパティ

JNDIのOracleデータソース・サポートの概要

JNDI標準は、リモート・サービスおよびリソースを検出してアクセスする方法をアプリケーションに提供します。これらのサービスは、エンタープライズ・サービスにも可能です。ただし、JDBCアプリケーションの場合は、これらのサービスにデータベース接続およびサービスが含まれます。

JNDIを使用すると、アプリケーションはアプリケーション・コードからベンダー固有の構文を削除し、論理名を使用してこれらのサービスにアクセスできます。JNDIには、目的のサービスの特定のソースと論理名を関連付ける機能があります。

すべてのOracle JDBCデータソースは、JNDIによる参照が可能です。開発者が必ずしもこの機能を使用する必要はありませんが、JNDI論理名を使用してデータベースにアクセスすると、コードの移植性が高まります。

注意:
JNDI機能の使用には、CLASSPATH環境変数にjndi.jarファイルが含まれている必要があります。このファイルは、Java製品とともにインストール・メディアに含まれています。CLASSPATH環境変数に、別個に追加する必要があります。Sun MicrosystemsのWebサイトからも入手できますが、Oracleドライバでテストされている、Oracleが提供するバージョンを使用することをお薦めします。

データソースの機能とプロパティ

JNDIを使用するデータソース機能では、ベンダー固有のJDBCドライバ・クラス名を登録する必要はなく、URLとその他のプロパティの論理名を使用できます。このため、データベース接続をオープンするためのコードは、他の環境に移植できます。

DataSourceインタフェースとOracleによる実装

JDBCデータソースは、標準javax.sql.DataSourceインタフェースを実装するクラスのインスタンスです。

public interface DataSource
{
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password)
throws SQLException;
...
}

Oracleでは、このインタフェースをoracle.jdbc.poolパッケージのOracleDataSourceクラスに実装しています。オーバーロードされたgetConnectionメソッドは、データベースへの接続を戻します。

他の値を使用するには、適切なsetterメソッドを使用してプロパティを設定します。代替のユーザー名とパスワードを設定するには、入力としてこれらのパラメータを取るgetConnectionメソッドを使用することもできます。この設定は、プロパティ設定よりも優先されます。

注意:
OracleDataSourceクラスとすべてのサブクラスは、java.io.Serializableインタフェースとjavax.naming.Referenceableインタフェースを実装します。

DataSourceのプロパティ

DataSourceインタフェースを実装するすべてのクラスと同様に、OracleDataSourceクラスは、接続するデータベースの指定に使用できる一連のプロパティを提供します。これらのプロパティはJavaBeansのデザインパターンに従います。

表8-1および表8-2は、OracleDataSourceプロパティを示しています。表8-1のプロパティは、Sun社の仕様に従った標準プロパティです。表8-2のプロパティはOracle拡張機能です。

注意:
Oracleは標準roleNameプロパティを実装していません。

表8-1 標準データソース・プロパティ

名前

型

説明

databaseName

String

サーバー上の特定のデータベース名。Oracleの用語ではSIDとも呼ばれます。

dataSourceName

String

基礎となるデータソース・クラスの名前。接続プーリングの場合、これはプーリングされた基礎となる接続データソース・クラスです。分散トランザクションの場合、これは基礎となるXAデータソース・クラスです。

description

String

データソースの説明。

networkProtocol

String

サーバーと通信するためのネットワーク・プロトコル。Oracleの場合、これはJDBC Oracle Call Interface(OCI)ドライバのみに適用され、デフォルトはtcpです。

password

String

接続するユーザーのパスワード。

portNumber

int

サーバーが要求をリスニングするポート番号。

serverName

String

データベース・サーバーの名前。

user

String

ログイン用の名前。

注意:
セキュリティ上の理由により、getPassword()メソッドはありません。

表8-2 Oracle拡張データソース・プロパティ

名前

型

説明

connectionCacheName

String

キャッシュの名前を指定します。キャッシュを作成した後は変更できません。

connectionCacheProperties

java.util.Properties

暗黙的接続キャッシュのプロパティを指定します。

connectionCachingEnabled

Boolean

暗黙的接続キャッシュが使用中かどうかを指定します。

connectionProperties

java.util.Properties

接続プロパティを指定します。

driverType

String

Oracle JDBCドライバのタイプを指定します。oci、thinまたはkprbのいずれかを指定します。

fastConnectionFailoverEnabled

Boolean

高速接続フェイルオーバーが使用中かどうかを指定します。

implicitCachingEnabled

Boolean

暗黙的文接続キャッシュが有効かどうかを指定します。

loginTimeout

int

このデータソースがデータベースへの接続の試行中に待機する最大時間(秒)を指定します。

logWriter

java.io.PrintWriter

このデータソースのログ・ライターを指定します。

maxStatements

int

アプリケーションのキャッシュ内に存在する文の最大数を指定します。

serviceName

String

このデータソースに対するデータベース・サービス名を指定します。

tnsEntry

String

TNSエントリ名を指定します。TNSエントリ名は、tnsnames.ora構成ファイルに指定されているTNSエントリに対応します。

OCIドライバでネイティブXA機能を使用する場合は、このOracleXADataSourceプロパティを有効に設定して、Oracleリリース8.1.6以降のデータベースにアクセスしてください。ネイティブXA機能を使用するときにtnsEntryプロパティが設定されていないと、エラー・コードORA-17207のSQLExceptionが発生します。

url

String

データベース接続文字列のURLを指定します。以前のバージョンのOracle Databaseから移行する際の便宜を考えて提供されるものです。Oracle tnsEntryおよびdriverTypeプロパティ、標準portNumber、networkProtocol、serverNameおよびdatabaseNameプロパティのかわりに、このプロパティを使用できます。

nativeXA

Boolean

OCIドライバでネイティブXA機能を使用する場合は、OracleXADataSourceを有効に設定して、Oracleリリース8.1.6以降のデータベースにアクセスしてください。nativeXAプロパティを有効にする場合は、必ずtnsEntryプロパティも設定してください。このプロパティはOracleXADatasource専用です。

このDataSourceプロパティは、デフォルトでfalseに設定されます。

ONSConfiguration

String

FAN/ONSイベントのリモートでのサブスクライブに使用するONS構成を指定します。

注意:

- この表では、非推奨となった接続キャッシュをOracleConnectionCacheに基づいてサポートしていたプロパティは省略されています。

- ネイティブXAは、Java XAよりパフォーマンスが高いため、可能なかぎりネイティブXAを使用してください。

setConnectionPropertiesメソッドを使用して接続のプロパティを設定し、setConnectionCachePropertiesメソッドを使用して接続キャッシュのプロパティを設定します。

接続のプロパティの詳細は、「サポートされている接続プロパティ」を参照してください。

接続キャッシュのプロパティの詳細は、「接続キャッシュ・プロパティ」を参照してください。

サーバー側内部ドライバを使用している場合、つまりdriverTypeプロパティがkprbに設定されている場合、その他のプロパティ設定は無視されます。

JDBC ThinドライバまたはOCIドライバを使用している場合は、次の点に注意してください。

- URL設定には、次の例のようにuserとpasswordの設定が含まれることがあります。この場合は、この設定が個々のuserおよびpasswordプロパティ設定よりも優先されます。

jdbc:oracle:thin:scott/tiger@localhost:1521:orcl

- userとpasswordは、URL設定を介して直接設定するか、またはgetConnectionコールを介して設定する必要があります。getConnectionコールによるuserとpasswordの設定は、他のプロパティ設定よりも優先されます。

- urlプロパティを設定した場合は、tnsEntry、driverType、portNumber、networkProtocol、serverNameおよびdatabaseNameプロパティ設定は無視されます。

- tnsEntryプロパティを設定した場合(urlプロパティは設定されていないものとします)、databaseName、serverName、portNumberおよびnetworkProtocolの各設定は無視されます。

- OCIドライバを使用しているときに(driverTypeプロパティはociに設定されているものとします)、networkProtocolがipcに設定されている場合、他のプロパティ設定は無視されます。

またgetConnectionCacheName()は、データソースのキャッシュが有効になった後でデータソースのConnectionCacheNameプロパティが設定された場合にのみキャッシュの名前を戻します。

データソース・インスタンスの作成と接続

この項では、JNDI機能を使用せずにデータベースに接続する場合の、データソースの最も基本的な使用例を示します。ベンダーによってはベンダー固有のハードコードされたプロパティ設定が必要であることに注意してください。

次の例のようにOracleDataSourceインスタンスを作成し、必要に応じて接続プロパティを初期化して、接続インスタンスを取得します。

OracleDataSource ods = new OracleDataSource();
ods.setDriverType("oci");
ods.setServerName("dlsun999");
ods.setNetworkProtocol("tcp");
ods.setDatabaseName("816");
ods.setPortNumber(1521);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

または、必要に応じて次のようにユーザー名とパスワードをオーバーライドします。

Connection conn = ods.getConnection("bill", "lion");

データソース・インスタンスの作成、JNDIへの登録および接続

この項では、データソースを使用してデータベースに接続する場合のJNDI機能を示します。ベンダー固有のハードコードされたプロパティ設定は、データソース・インスタンスをJNDI論理名にバインドするコードの部分でのみ必要になります。これ以降は、接続インスタンスを取得するデータソースを作成するために、論理名を使用して、移植可能なコードを作成できます。

注意:
データソースの作成と登録は、一般にJDBCアプリケーションではなく、JNDI管理者によって処理されます。

データソース・プロパティの初期化

次の例に示すように、OracleDataSourceインスタンスを作成し、必要に応じてそのプロパティを初期化します。

OracleDataSource ods = new OracleDataSource();
ods.setDriverType("oci");
ods.setServerName("dlsun999");
ods.setNetworkProtocol("tcp");
ods.setDatabaseName("816");
ods.setPortNumber(1521);
ods.setUser("scott");
ods.setPassword("tiger");

データソースの登録

前述の例で示したように、OracleDataSourceインスタンスodsの接続プロパティを初期化した後は、次の例に示すように、このデータソース・インスタンスをJNDIに登録できます。

Context ctx = new InitialContext();
ctx.bind("jdbc/sampledb", ods);

JNDI InitialContext()コンストラクタをコールすると、初期JNDIネーミング・コンテキストを参照するJavaオブジェクトが作成されます。表示されていないシステム・プロパティによって、使用するサービス・プロバイダがJNDIに指示されます。

ctx.bindコールは、OracleDataSourceインスタンスを論理JNDI名にバインドします。つまり、ctx.bindをコールした後、いつでも論理名jdbc/sampledbを使用して、OracleDataSourceインスタンスodsのプロパティによって記述されるデータベースへの接続をオープンできます。論理名jdbc/sampledbは、このデータベースに論理的にバインドされます。

JNDIネームスペースの階層構造は、ファイルシステムの階層構造と似ています。この例で、JNDI名はルート・ネーミング・コンテキストでサブコンテキストjdbcを指定し、jdbcサブコンテキスト内で論理名sampledbを指定します。

ContextインスタンスとInitialContextクラスは、標準javax.namingパッケージ内にあります。

注意:
JDBC 2.0仕様では、すべてのJDBCデータソースを、JNDIネームスペースのjdbcネーミング・サブコンテキスト、またはjdbcサブコンテキストの子サブコンテキストに登録する必要があります。

接続のオープン

lookupを実行して、JNDI名に論理的にバインドされたデータベースへの接続をオープンするには、論理JNDI名を使用します。これを実行するには、lookupの結果(Java Objectも可)をOracleDataSourceにキャストし、そのgetConnectionメソッドを使用して接続をオープンします。

次に例を示します。

OracleDataSource odsconn = (OracleDataSource)ctx.lookup("jdbc/sampledb");
Connection conn = odsconn.getConnection();

サポートされている接続プロパティ

Oracle JDBCドライバがサポートする接続プロパティの詳細は、Javadocを参照してください。

SYSログインのためのロールの使用方法

SYSでログオンするためのロールを指定するには、internal_logon接続プロパティを使用します。SYSでログオンするには、internal_logon接続プロパティを、SYSDBAまたはSYSOPERに設定します。

Bequeathed接続の場合、internal_logonプロパティを設定することにより、SYSとして接続を取得できます。リモート接続の場合、追加でパスワード・ファイルの設定手順を実行する必要があります。

データベース・リモート・ログインの構成

JDBC ThinドライバがSYSDBAとしてデータベースに接続できるようにするには、ユーザーを構成する必要があります。Oracle Databaseのセキュリティ・システムで管理者としてリモート接続するためにはパスワード・ファイルが必要です。次の手順を実行します。

1. orapwdパスワード・ユーティリティを使用してサーバー側またはリモート・データベースでパスワード・ファイルを設定します。ユーザーsysのパスワード・ファイルを追加するには、次のようにします。

- UNIXの場合

orapwd file=$ORACLE_HOME/dbs/orapw entries=200
Enter password: password

- Microsoft Windowsの場合

orapwd file=%ORACLE_HOME%\database\PWDsid_name.ora entries=200
Enter password: password

fileは、パスワード・ファイルの名前にする必要があります。passwordは、ユーザーSYSのためのパスワードです。SQL Plusでは、ALTER USER文を使用して変更することができます。entriesは、想定されるエントリ数より大きな値に設定してください。

パスワード・ファイル名の構文は、Microsoft WindowsとUNIXでは異なります。

関連項目:
『Oracle Database管理者ガイド』

2. sysdbaとしてリモート・ログインを有効にします。この手順では、SYSDBAおよびSYSOPERシステム権限を個別のユーザーに付与し、それらのユーザーがそのままのユーザーとして接続できるようにします。
データベースを停止し、次の行を、UNIXの場合はinitservice_name.oraに、Microsoft Windowsの場合はinit.oraに追加します。

remote_login_passwordfile=exclusive

initservice_name.oraファイルは、ORACLE_HOME/dbs/およびORACLE_HOME/admin/db_name/pfile/に存在します。これらの2つのファイルは同期化してください。

init.oraファイルは、%ORACLE_BASE%\ADMIN\db_name\pfile\に存在します。

3. SYSユーザーのパスワードを変更します。これは省略可能な手順です。

PASSWORD sys
Changing password for sys
New password: password
Retype new password: password

4. SYSがSYSDBA権限を持っていることを確認します。

SQL> select * from v$pwfile_users;
USERNAME                         SYSDB        SYSOP
----------------------           ---------    ---------
SYS                              TRUE         TRUE

5. リモート・データベースを再起動します。

例8-1 リモート接続でのSYSログインの使用

//This example works regardless of language settings of the database.
/** case of remote connection using sys **/
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
// create an OracleDataSource
OracleDataSource ods = new OracleDataSource();
// set connection properties
java.util.Properties prop = new java.util.Properties();
prop.put("user", "sys");
prop.put("password", "sys");
prop.put("internal_logon", "sysoper");
ods.setConnectionProperties(prop);
// set the url
// the url can use oci driver as well as:
// url = "jdbc:oracle:oci8:@inst1"; the inst1 is a remote database
String url = "jdbc:oracle:thin:@//myHost:1521/service_name";
ods.setURL(url);
// get the connection
Connection conn = ods.getConnection();
...

Bequeathed接続とSYSログオン

次の例は、SYSログインを指定するための、internal_logonおよびSYSDBA引数の使用方法を示しています。この例は、データベースの各国語設定に関係なく動作します。

/** Example of bequeath connection **/
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;

// create an OracleDataSource instance
OracleDataSource ods = new OracleDataSource();

// set neccessary properties
java.util.Properties prop = new java.util.Properties();
prop.put("user", "sys");
prop.put("password", "sys");
prop.put("internal_logon", "sysdba");
ods.setConnectionProperties(prop);

// the url for bequeath connection
String url = "jdbc:oracle:oci8:@";
ods.setURL(url);

// retrieve the connection
Connection conn = ods.getConnection();
...

Oracleパフォーマンス拡張要素のプロパティ

接続プロパティの一部は、Oracleパフォーマンス拡張機能で使用します。これらのプロパティの設定は、次のようにOracleConnectionオブジェクトで対応するメソッドを使用することと同等です。

- defaultRowPrefetchプロパティの設定は、setDefaultRowPrefetchのコールと同等です。

- remarksReportingプロパティの設定は、setRemarksReportingのコールと同等です。

関連項目:
「DatabaseMetaData TABLE_REMARKSのレポート」

- defaultBatchValueプロパティの設定は、setDefaultExecuteBatchコールと同等です。

関連項目:
「Oracleバッチ更新」

例

次の例は、java.util.Propertiesクラスのputメソッドの使用方法を示します。この例では、Oracleパフォーマンス拡張要素のパラメータを設定する方法を示します。

//import packages and register the driver
import java.sql.*;
import java.math.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;

//specify the properties object
java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password", "tiger");
info.put ("defaultRowPrefetch","20");
info.put ("defaultBatchValue", "5");

//specify the datasource object
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@//myhost:1521/orcl");
ods.setUser("scott");
ods.setPassword("tiger");
ods.setConnectionProperties(info);
...

データベースURLとデータベース指定子

データベースURLは文字列です。完全なURL構文は、次のとおりです。

jdbc:oracle:driver_type:[username/password]@database_specifier

注意:

- 大カッコは、username/passwordペアがオプションであることを示します。

- 内部サーバー側ドライバkprbは、暗黙的な接続を使用します。サーバー側ドライバのデータベースURLはdriver_typeで終わります。

URLの最初の部分では、使用するJDBCドライバを指定します。サポートされているdriver_type値は、thin、ociおよびkprbです。

URLの残りの部分には、スラッシュで区切られたユーザー名とパスワード(オプション)、@、およびアプリケーションが接続されるデータベースを一意に識別するデータベース指定子が含まれます。データベース指定子には、JDBC Thinドライバにのみ有効なもの、JDBC OCIドライバにのみ有効なもの、両方に有効なものがあります。

インターネット・プロトコル・バージョン6のサポート

Oracle JDBCドライバの今回のリリースでは、インターネット・プロトコル・バージョン6(IPv6)のアドレスを、JDBC URLとIPv6のアドレスに解決するマシン名でサポートします。IPv6は、現行のインターネット・プロトコルであるインターネット・プロトコル・バージョン4(IPv4)にかわるものとして、Internet Engineering Task Force(IETF)によって設計された新しいネットワーク層プロトコルです。IPv6の主な利点は、128ビット・アドレスの使用による大きなアドレス空間です。IPv6はまた、ルーティング、ネットワーク自動構成、セキュリティ、サービス品質などの点でも、IPv4より改善されています。

URLでリテラルIPv6アドレスを使用する場合は、リテラル・アドレスを左の大カッコ([)と右の大カッコ(])で囲む必要があります。たとえば、[2001:0db8:7654:3210:FEDC:BA98:7654:3210]のようになります。したがって、IPv6アドレスを使用するJDBC URLは、次のようになります。

jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)
(HOST=[2001:0db8:7654:3210:FEDC:BA98:7654:3210])(PORT=5521))
(CONNECT_DATA=(SERVICE_NAME=sales.example.com))

注意:
IPv6のサポートに必要な新しいシステム・クラスはすべて、データベースの初期化中に有効になります。したがって、アプリケーションにIPv6アドレスがない場合は、IPv6機能を使用するために自分のコードを変更する必要はありません。ただし、アプリケーションにIPv6アドレスのみか、IPv6とIPv4アドレスの両方のいずれかがある場合、コマンドラインでjava.net.preferIPv6Addressesシステム・プロパティを設定する必要があります。これにより、Oracle JVMは適切なライブラリをロードできるようになります。これらのライブラリは一度ロードすると、Javaプロセスを再起動しないかぎりリロードできません。このシステム・プロパティの詳細は、『Oracle Database Java開発者ガイド』を参照してください。

データベース指定子

表8-3は、データベース指定子と各指定子がサポートするJDBCドライバを示しています。

注意:

- Oracle Database 10gでは、Oracle Service IDはサポートされません。

- Oracle Database 10g以降、ネーミング・メソッドとしてのOracle Namesはサポートされなくなりました。

表8-3 サポートされるデータベース指定子

指定子

サポートするドライバ

例

Oracle Net接続記述子

Thin、OCI

Thinの場合。アドレス・リストを使用します。

url="jdbc:oracle:thin:@(DESCRIPTION=
(LOAD_BALANCE=on)
(ADDRESS_LIST=
(ADDRESS=(PROTOCOL=TCP)(HOST=host1) (PORT=1521))
(ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME=service_name)))"

OCIの場合。クラスタを使用します。

"jdbc:oracle:oci:@(DESCRIPTION=
(ADDRESS=(PROTOCOL=TCP)(HOST=cluster_alias)
(PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=service_name)))"

Thin形式のサービス名

Thin

詳細は、「Thin形式のサービス名の構文」を参照してください。

"jdbc:oracle:thin:scott/tiger@//myhost:1521/myservicename"

LDAP構文

Thin

詳細は、LDAP構文を参照してください。

"jdbc:oracle:thin:@ldap://ldap.example.com:7777/sales,cn=OracleContext,dc=com"

Bequeathed接続

OCI

空。つまり、@の後には何も記述しません。

"jdbc:oracle:oci:scott/tiger/@"

TNSNames別名

Thin、OCI

詳細は、「TNSNames別名の構文」を参照してください。

OracleDataSource ods = new OracleDataSource();
ods.setTNSEntryName("MyTNSAlias");

Thin形式のサービス名の構文

Thin形式のサービス名は、JDBC Thinドライバでのみサポートされます。構文は次のとおりです。

@//host_name:port_number/service_name

たとえば、次のようになります。

jdbc:oracle:thin:scott/tiger@//myhost:1521/myservicename

注意:
JDBC Thinドライバは、TCP/IPプロトコルのみをサポートします。

TNSNames別名の構文

接続元のクライアント・コンピュータ上のtnsnames.oraファイルにリストされた、利用可能なTNSNAMESエントリを検索できます。Windowsの場合、このファイルはORACLE_HOME\NETWORK\ADMINディレクトリにあります。UNIXシステムの場合は、ORACLE_HOMEディレクトリ、またはTNS_ADMIN環境変数に示されているディレクトリに格納されています。

たとえば、ホストmyhost上のデータベースに、ユーザーscott、パスワードtiger(MyHostStringのTNSNAMESエントリを持つ)で接続する場合は、次のように記述します。

OracleDataSource ods = new OracleDataSource();
ods.setTNSEntryName("MyTNSAlias");
ods.setUser("scott");
ods.setPassword("tiger");
ods.setDriverType("oci");
Connection conn = ods.getConnection();

JDBC Thinドライバがtnsnames.oraファイルの位置を確認できるように、oracle.net.tns_adminシステム・プロパティをtnsnames.oraファイルの位置に設定する必要があります。たとえば、次のようになります。

System.setProperty("oracle.net.tns_admin", "c:\\Temp");
String url = "jdbc:oracle:thin:@tns_entry";

注意:
TNSNamesをJDBC Thinドライバとともに使用する場合は、oracle.net.tns_adminプロパティをtnsnames.oraファイルのあるディレクトリに設定する必要があります。

java -Doracle.net.tns_admin=$ORACLE_HOME/network/admin

LDAP構文

Lightweight Directory Access Protocol(LDAP)構文を使用するデータベース指定子の例を次に示します。

"jdbc:oracle:thin:@ldap://ldap.example.com:7777/sales,cn=OracleContext,dc=com"

SSLを使用する場合は、これを次のように変更します。

"jdbc:oracle:thin:@ldaps://ldap.example.com:7777/sales,cn=OracleContext,dc=com"

注意:
JDBC Thinドライバの場合、データベース指定子のldap:をldaps:に置き換えると、LDAPを使用し、SSLを介してOracle Internet Directoryと通信できます。LDAPサーバーは、SSLを使用するように構成されている必要があります。構成されていない場合は、接続に失敗します。

JDBC Thinドライバは、サービス名解決プロセスの際、LDAPサーバーのリストのフェイルオーバーをサポートします。ハードウェア・ロード・バランサは必要ありません。また、クライアント側ロード・バランシングが、LDAPサーバーへの接続のためにサポートされます。フェイルオーバーとロード・バランシングをサポートするために、スペースで区切られたLDAP URL構文のリストが使用されます。

LDAP URLのリストを指定すると、フェイルオーバーとロード・バランシングの両方がデフォルトで有効になります。oracle.net.ldap_loadbalance接続プロパティを使用するとロード・バランシングを無効にでき、oracle.net.ldap_failover接続プロパティを使用するとフェイルオーバーを無効にできます。

フェイルオーバーを使用するが、クライアント側ロード・バランシングを無効にする例を次に示します。

Properties prop = new Properties();
String url = "jdbc:oracle:thin:@ldap://ldap1.example.com:3500/cn=salesdept,cn=OracleContext,dc=com/salesdb " +
"ldap://ldap2.example.com:3500/cn=salesdept,cn=OracleContext,dc=com/salesdb " +
"ldap://ldap3.example.com:3500/cn=salesdept,cn=OracleContext,dc=com/salesdb";

prop.put("oracle.net.ldap_loadbalance", "OFF" );
OracleDataSource ods = new OracleDataSource();
ods.setURL(url);
ods.setConnectionProperties(prop);

JDBC ThinドライバはLDAP非匿名バインドをサポートします。データソースに対して、認証情報を含む一連のJNDI環境プロパティを指定できます。LDAPサーバーが匿名バインドを許可しないよう設定されている場合は、LDAPサーバーに接続するために認証情報を提供する必要があります。次の例は、簡単なクリアテキストのパスワード認証を示しています。

String url = "jdbc:oracle:thin:@ldap://ldap.example.com:7777/sales,cn=salesdept,cn=OracleContext,dc=com";

Properties prop = new Properties();
prop.put("java.naming.security.authentication", "simple");
prop.put("java.naming.security.principal","cn=salesdept,cn=OracleContext,dc=com");
prop.put("java.naming.security.credentials", "mysecret");

OracleDataSource ods = new OracleDataSource();
ods.setURL(url);
ods.setConnectionProperties(prop);

JDBCがJNDIに3つのプロパティを渡すので、クライアントで選択される認証メカニズムが、これらのプロパティのJNDIでの解釈方法と矛盾することはありません。たとえば、クライアントがjava.naming.security.authenticationプロパティを明示的に指定せずに認証情報を指定する場合、デフォルトの認証メカニズムは簡易認証です。詳細は、関連のJDNIドキュメントを参照してください。

9 JDBCクライアント側セキュリティ機能

この章では、Oracle Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバとJDBC Thinドライバによるログイン認証、データ暗号化およびデータ整合性のサポートについて、特にOracle Advanced Securityオプションの機能の観点から説明します。

以前Advanced Networking Option(ANO)またはAdvanced Security Option(ASO)と呼ばれていたOracle Advanced Securityは、業界標準に基づくデータ暗号化、データ整合性、サード・パーティ認証、シングル・サインオンおよびアクセス認可の機能を提供します。11gリリース2(11.2)では、JDBC OCIドライバとJDBC Thinドライバの両方で、Oracle Advanced Securityの機能をすべてサポートしています。以前のリリースのJDBCドライバでは、ASOの一部の機能をサポートしていませんでした。

注意:
サーバー側内部ドライバを介したすべての通信が完全にサーバー内で行われるため、この説明はサーバー側内部ドライバには関係しません。

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

- Oracle Advanced Securityのサポート

- ログイン認証のサポート

- 厳密認証のサポート

- OS認証のサポート

- データ暗号化と整合性のサポート

- SSLのサポート

- Kerberosのサポート

- RADIUSのサポート

- セキュアな外部パスワード記憶域

Oracle Advanced Securityのサポート

Oracle Advanced Securityでは、次のセキュリティ機能をサポートしています。

- データ暗号化
エンタープライズ・ネットワークおよびインターネット上でやりとりされる機密情報は、復号化キーによってのみ解読できる形式に情報を変換する暗号化アルゴリズムにより保護できます。サポートされている暗号化アルゴリズムには、RC4、DES、3DES、AESなどがあります。

伝送時のデータ整合性を確保するために、Oracle Advanced SecurityではMD5やSHA-1のハッシング・アルゴリズムを使用して暗号化の見地から安全なメッセージ・ダイジェストを作成し、それをネットワーク上で送信される各メッセージに含めます。これにより、やりとりされるデータは、データの変更、パケットの削除、反射攻撃などの攻撃から保護されます。

- 厳密認証
分散環境でネットワーク・セキュリティを確保するには、ユーザーを認証し、資格証明を確認する必要があります。パスワード認証は、認証で最も一般的な手段です。Oracle Advanced Securityでは、Oracle認証アダプタを使用して厳密な認証を行います。Oracle認証アダプタは、デジタル証明書を使用したSSLを含む様々なサード・パーティ認証サービスをサポートします。 Oracle Advanced Securityは、業界で標準的な次の認証方式をサポートしています。

- Kerberos

- Remote Authentication Dial-In User Service(RADIUS)

- Secure Sockets Layer(SSL)

ヒント:
『Oracle Database Advanced Security管理者ガイド』

JDBC OCIドライバによるOracle Advanced Securityのサポート

JDBC OCIドライバを使用している場合は、Oracleクライアントがインストールされているコンピュータから実行していることが想定されるため、Oracle Advanced Securityと組込みサード・パーティ機能のサポートは、Oracleクライアントによって提供されるサポートとほとんど同じです。Advanced Security機能が使用されているかどうかは、クライアント・コンピュータのsqlnet.oraファイル内の、関連する設定の内容によって判断できます。

Oracle Database 11gリリース1 (11.1)以上では、パスワードを入力しないでデータベースに接続しようとすると、JDBC OCIドライバは外部認証を使用しようとします。JDBC OCIドライバを使用して、パスワードを入力しないでデータベースに接続する例を次に示します。

SSL認証

例9-1は、SSL認証を使用してデータベースに接続する例です。

例9-1 SSL認証を使用したデータベースへの接続

import java.sql.*;
import java.util.Properties;

public class test
{
public static void main( String [] args ) throws Exception
{
String url = "jdbc:oracle:oci:@"
+"(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=stadh25)(PORT=1529))"
+"(CONNECT_DATA=(SERVICE_NAME=mydatabaseinstance)))";
Driver driver = new oracle.jdbc.OracleDriver();
Properties props = new Properties();
Connection conn = driver.connect( url, props );
conn.close();
}
}

データソースの使用

例9-2は、データソースを使用してデータベースに接続する例です。

例9-2 データソースを使用したデータベースへの接続

import java.sql.*;
import javax.sql.*;
import java.util.Properties;
import oracle.jdbc.pool.*;

public class testpool {
public static void main( String args ) throws Exception
{ String url = "jdbc:oracle:oci:@" +"(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=stadh25)(PORT=1529))"
+"(CONNECT_DATA=(SERVICE_NAME=mydatabaseinstance)))";
OracleConnectionPoolDataSource ocpds = new OracleConnectionPoolDataSource();
ocpds.setURL(url);
PooledConnection pc = ocpds.getPooledConnection();
Connection conn = pc.getConnection();
}
}

JDBC ThinドライバによるOracle Advanced Securityのサポート

JDBC Thinドライバでは、Oracleクライアントがインストールされていること、またはsqlnet.oraファイルが存在していることを前もって想定できません。したがって、Javaアプローチを使用してOracle Advanced Securityをサポートします。Oracle Advanced Securityを実装するJavaクラスは、ojdbc5.jarファイルおよびojdbc6.jarファイルに含まれています。暗号化と整合性のためのセキュリティ・パラメータは、通常のようにsqlnet.ora内に設定されるのではなく、JavaのPropertiesオブジェクトか、またはシステム・プロパティを使用して設定されます。

ログイン認証のサポート

JDBCを介した基本ログイン認証では、Oracleサーバーへの他のログイン方法と同様に、ユーザー名とパスワードが要求されます。Javaプロパティ・オブジェクトを使用するか、またはgetConnectionメソッドを直接コールして、ユーザー名とパスワードを指定します。これは、使用しているクライアント側Oracle JDBCドライバにかかわらず適用されますが、サーバー側内部ドライバを使用している場合には、特殊な直接接続を使用しており、ユーザー名またはパスワードを要求しないため、関係ありません。

11gリリース1 (11.1)以降、Oracle JDBC Thinドライバには、ユーザーを認証する方式としてチャレンジ・レスポンス・プロトコルが実装されています。

厳密認証のサポート

Oracle Advanced Securityでは、Oracle Databaseユーザーに対する外部認証が可能です。外部認証には、RADIUS、KERBEROS、証明書ベースの認証、トークン・カードおよびスマート・カードなどが使用されます。この認証方法は、厳密認証と呼ばれます。Oracle JDBCドライバでサポートしている厳密認証方法は次のとおりです。

- Kerberos

- RADIUS

- SSL(証明書ベースの認証)

OS認証のサポート

オペレーティング・システム(OS)認証を使用すると、Oracleで、オペレーティング・システムにユーザー認証の制御を渡すことができます。ユーザーは、データベース内のOSユーザー名を認証することによってデータベースに接続できます。OS認証で十分であると想定されるため、アカウントにはパスワードが関連付けられていません。つまり、サーバーはクライアントOSに認証を委任します。この状態にするには次の手順を実行する必要があります。

- 次のコマンドを使用してOracle OS_AUTHENT_PREFIX初期化パラメータの値をチェックします。

SQL> SHOW PARAMETER os_authent_prefix
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
os_authent_prefix                    string      ops$
SQL>

注意:
OS認証の接頭辞を忘れないようにしてください。OS認証接続を許可するにはデータベース・ユーザーを作成する必要がありますが、そのユーザー名は、接頭辞値とOSのユーザー名を連結したものである必要があります。

- t_init1.oraファイルに次の行を追加します。

REMOTE_OS_AUTHENT = TRUE

ローカル・データベース・サーバーから接続を試みると、OSユーザー名がOracleサーバーに渡されます。ユーザー名が認識されると接続が許可され、それ以外の場合、接続は拒否されます。

Linuxの構成手順

Linux上でOS認証を設定するために必要な設定手順は次のとおりです。

1. 次のコマンドを使用してOSユーザーw_roseを作成します。

# useradd w_rose
# passwd w_rose
Changing password for w_rose
New password: password
Retype new password: password

2. 次のコマンドを使用してデータベース・ユーザーを作成し、OS認証接続を許可します。

CREATE USER ops$w_rose IDENTIFIED EXTERNALLY;
GRANT CONNECT TO ops$w_rose;

3. 次のコマンドを使用してOS認証接続をテストします。

su - w_rose
export ORACLE_HOME=/u01/app/oracle/product/10.1.0/db_1
export PATH=$PATH:$ORACLE_HOME/bin
export ORACLE_SID=DEV1
sqlplus /

SQL*Plus: Release 10.1.0.3.0 - Production on Wed Jun 7 08:41:15 2006

Copyright (c) 1982, 2004, Oracle.  All rights reserved.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Data Mining options

SQL>

Windowsの構成手順

Windows上でOS認証を設定するために必要な設定手順は次のとおりです。

注意:
Oracle JDBC Thinドライバは、NTSをサポートしません。

1. 「コンピュータの管理」ダイアログ・ボックスを使用してローカル・ユーザー(たとえばw_rose)を作成します。手順は次のとおりです。

1. 「スタート」をクリックします。

2. 「スタート」メニューから「プログラム」、「管理ツール」、「コンピュータの管理」の順に選択します。

3. プラス(「+」)記号をクリックして「ローカル ユーザーとグループ」を展開します。

4. 「ユーザー」をクリックします。

5. 「操作」メニューから「新しいユーザー」を選択します。

6. ユーザーの詳細を「新しいユーザー」ダイアログ・ボックスに入力し、「作成」をクリックします。

注意:
前の手順で作成されるのは、ローカル・ユーザーのみです。ドメイン・ユーザーはActive Directoryで作成できます。

2. 次のコマンドを使用してデータベース・ユーザーを作成し、OS認証接続を許可します。

CREATE USER "OPS$yourdomain.com\p_floyd" IDENTIFIED EXTERNALLY;
GRANT CONNECT TO "OPS$yourdomain.com\p_floyd";

注意:
Windows環境でデータベース・ユーザーを作成する場合、ユーザー名は次の形式にします。

<OS_authentication_prefix_parameter>$<DOMAIN>\<OS_user_name>

Windowsサーバーを使用する場合は、他にも検討事項があります。%ORACLE_HOME%\network\admin\sqlnet.oraファイルで次のオプションを設定する必要があります。

SQLNET.AUTHENTICATION_SERVICES= (NTS)

3. 次のコマンドを使用してOS認証接続をテストします。

C:\> set ORACLE_SID=DB11G
C:\> sqlplus /
SQL*Plus: Release 11.2.0.1.0 - Production on Thu July 12 11:47:01 2007
Copyright (c) 1982, 2008, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>

OS認証を使用するJDBCコード

データベースに接続するためのOS認証の設定が完了したので、次のJDBCコードを使用してデータベースに接続することができます。

String url = "jdbc:oracle:thin:@oracleserver.mydomain.com:5521:dbja"
Driver driver = new oracle.jdbc.OracleDriver();
DriverManager.registerDriver(driver);
Properties props = new Properties();
Connection conn = DriverManager.getConnection( url, props);

このコードは、クライアント・マシンでp_floydによって実行されると想定しています。JDBCドライバは、JVMによって設定されるuser.nameシステム・プロパティからOSユーザー名を取得します。その結果、Thinドライバ固有の次のエラーはなくなります。

ORA-17443=Null user or password not supported in THIN driver

注意:
デフォルトで、JDBCドライバは、JVMによって設定されるuser.nameシステム・プロパティからOSユーザー名を取得します。JDBCドライバがこのシステム・プロパティを取得できない場合、またはこのシステム・プロパティの値をオーバーライドする場合は、OracleConnection.CONNECTION_PROPERTY_THIN_VSESSION_OSUSER接続プロパティを使用することができます。詳細は、次のWebサイトにあるOracle Javadocを参照してください。

http://download.oracle.com/otn/utilities_drivers/jdbc/111060/doc/javadoc/index.html

データ暗号化と整合性のサポート

サーバーの関連部分の設定によっては、Javaデータベース・アプリケーションで、Oracle Advanced Securityのデータ暗号化および整合化機能を使用できます。JDBC OCIドライバを使用している場合は、Oracleクライアントの場合と同様にパラメータを設定します。Thinドライバを使用している場合は、Javaプロパティ・オブジェクトを使用してパラメータを設定します。

暗号化は、クライアント側暗号化レベル設定と、サーバー側暗号化レベル設定の組合せに基づいて、有効または無効になります。同様に、整合性はクライアント側整合性レベル設定と、サーバー側整合性レベル設定の組合せに基づいて、有効または無効になります。

暗号化と整合性は、REJECTED、ACCEPTED、REQUESTEDおよびREQUIREDの同じ設定レベルをサポートしています。表9-1は、クライアント側とサーバー側の設定の組合せごとに、この機能がオンになるかオフになるかを示しています。リモートOS認証(TCP経由)はセキュリティ上問題があるため、デフォルトで無効にされています。

表9-1 暗号化または整合性のためのクライアント/サーバー間ネゴシエーション

クライアントRejected

クライアントAccepted(デフォルト)

クライアントRequested

クライアントRequired

サーバーRejected

OFF

OFF

OFF

接続に失敗

サーバーAccepted(デフォルト)

OFF

OFF

ON

ON

サーバーRequested

OFF

ON

ON

ON

サーバーRequired

接続に失敗

ON

ON

ON

表9-1が示すように、たとえば、クライアントが暗号化を要求し、サーバーが拒否した場合は、暗号化はオフになります。整合性の場合も同様です。逆に、サーバーが暗号化を要求し、クライアントが受け入れる場合は、暗号化はオンになります。整合性の場合も同様です。

関連項目:
『Oracle Database Advanced Security管理者ガイド』

注意:
整合性パラメータ名には、まだchecksumという用語が使用されていますが、この用語はパラメータ以外では使用されません。事実上、checksumとintegrityはシノニムです。

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

- JDBC OCIドライバによるデータ暗号化と整合性のサポート

- JDBC Thinドライバによるデータ暗号化と整合性のサポート

- Javaでの暗号化および整合性パラメータの設定

JDBC OCIドライバによるデータ暗号化と整合性のサポート

JDBC OCIドライバを使用している場合は、Oracleクライアントのインストールを伴うOracleクライアント設定が想定されるため、クライアントのSQLNET.ORAファイルの設定によって、すべてのOracleクライアントの場合と同様に、データの暗号化または整合性を使用可能または使用禁止にし、関連するパラメータを設定できます。

表9-2に、クライアント・パラメータについてまとめます。

表9-2 暗号化と整合性のためのOCIドライバ・クライアント・パラメータ

パラメータの説明

パラメータ名

可能な設定

クライアント暗号化レベル

SQLNET.ENCRYPTION_CLIENT

REJECTED ACCEPTED REQUESTED REQUIRED

クライアント暗号化選択リスト

SQLNET.ENCRYPTION_TYPES_CLIENT

RC4_40、RC4_56、DES、DES40、AES128、AES192、AES256、3DES112、3DES168

(「注意」を参照)

クライアント整合性レベル

SQLNET.CRYPTO_CHECKSUM_CLIENT

REJECTED ACCEPTED REQUESTED REQUIRED

クライアント整合性選択リスト

SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT

MD5、SHA-1

注意:
Oracle Advanced Securityの国内版についてのみ、RC4_128およびRC4_256の設定も使用できます。

関連項目:
『Oracle Database Advanced Security管理者ガイド』

JDBC Thinドライバによるデータ暗号化と整合性のサポート

JDBC Thinドライバによるデータ暗号化および整合性パラメータ設定のサポートは、前の項で説明したJDBC OCIドライバ・サポートに対応しています。対応するパラメータは、データベース接続をオープンするときに使用するJavaプロパティ・オブジェクトを使用して設定できます。

表9-3は、JDBC Thinドライバのパラメータ情報です。これらのパラメータは、oracle.jdbc.OracleConnectionインタフェースで定義されています。

表9-3 暗号化と整合性のためのThinドライバ・クライアント・パラメータ

パラメータ名

パラメータ・タイプ

可能な設定

CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_LEVEL

String

REJECTED ACCEPTED REQUESTED REQUIRED

CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_TYPES

String

AES256、AES192、AES128、3DES168、3DES112、DES56C、DES40C、RC4_256、RC4_128、RC4_40、RC4_56

CONNECTION_PROPERTY_THIN_NET_CHECKSUM_LEVEL

String

REJECTED ACCEPTED REQUESTED REQUIRED

CONNECTION_PROPERTY_THIN_NET_CHECKSUM_TYPES

String

MD5、SHA1

注意:

- ThinドライバでのOracle Advanced Securityのサポートは、JDBCクラスJARファイルに直接組み込まれているため、1つのバージョンのみが存在し、国内版と輸出版にわかれてはいません。輸出版には適するパラメータ設定のみを使用できます。

- DES40CとDES56CのCの文字は、Cipher Block Chaining(CBC)モードを示しています。

Javaでの暗号化および整合性パラメータの設定

JDBC Thinドライバがサポートするデータ暗号化および整合性パラメータを設定するには、Javaプロパティ・オブジェクト、つまりjava.util.Propertiesのインスタンスを使用します。

次の例では、Javaプロパティ・オブジェクトをインスタンス化し、それを使用して表9-3の各パラメータを設定し、その後そのプロパティ・オブジェクトを使用してデータベース接続をオープンしています。

...
Properties prop = new Properties();
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_LEVEL, "REQUIRED");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_TYPES, "( DES40C )");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CHECKSUM_LEVEL, "REQUESTED");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CHECKSUM_TYPES, "( MD5 )");

OracleDataSource ods = new OracleDataSource();
ods.setProperties(prop);
ods.setURL("jdbc:oracle:thin:@localhost:1521:main");
Connection conn = ods.getConnection();
...

暗号化タイプおよびチェックサム・タイプの値は、丸カッコで囲み、リスト形式で指定できます。複数の値を指定した場合は、サーバーとクライアントの間のネゴシエーションにより、実際に使用される値が決定されます。

例

例9-3は、データベースに接続して問合せを実行する前に、データ暗号化とデータ整合性のパラメータを設定する完全なクラスの例です。

注意:
この例にある文字列「REQUIRED」は、AnoServicesクラスとServiceクラスの機能によって動的に取り出されます。この方法で文字列を取り出すことも、前の例のようにソフトウェア・コードに含めることもできます。

この例を実行する前に、sqlnet.oraファイルで暗号化を有効にする必要があります。たとえば、次のコードは、暗号化についてAES256、AES192およびAES128を、チェックサムについてはMD5とSHA1をオンにする場合の例です。

SQLNET.ENCRYPTION_SERVER = ACCEPTED
SQLNET.CRYPTO_CHECKSUM_SERVER = ACCEPTED
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER= (MD5, SHA1)
SQLNET.ENCRYPTION_TYPES_SERVER= (AES256, AES192, AES128)
SQLNET.CRYPTO_SEED = 2z0hslkdharUJCFtkwbjOLbgwsj7vkqt3bGoUylihnvkhgkdsbdskkKGhdk

例9-3 データ暗号化および整合性パラメータの設定

import java.sql.*;
import java.util.Properties;
import oracle.net.ano.AnoServices;
import oracle.jdbc.*;

public class DemoAESAndSHA1
{
static final String USERNAME= "scott";
static final String PASSWORD= "tiger";
static final String URL = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=WXYZ)(PORT=5561))"
+"(CONNECT_DATA=(SERVICE_NAME=mydatabaseinstance)))";

public static final void main(String[] argv)
{
DemoAESAndSHA1 demo = new DemoAESAndSHA1();
try
{
demo.run();
}catch(SQLException ex)
{
ex.printStackTrace();
}
}

void run() throws SQLException
{
OracleDriver dr = new OracleDriver();
Properties prop = new Properties();

// We require the connection to be encrypted with either AES256 or AES192.
// If the database doesn't accept such a security level, then the connection attempt will fail.

prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_LEVEL,AnoServices.ANO_REQUIRED);
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_TYPES,"( " + AnoServices.ENCRYPTION_AES256
+ "," + AnoServices.ENCRYPTION_AES192 + ")");

// We also require the use of the SHA1 algorithm for data integrity checking.

prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CHECKSUM_LEVEL,AnoServices.ANO_REQUIRED);
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CHECKSUM_TYPES,
"( " + AnoServices.CHECKSUM_SHA1 + " )");
prop.setProperty("user",DemoAESAndSHA1.USERNAME);
prop.setProperty("password",DemoAESAndSHA1.PASSWORD);
OracleConnection oraConn = (OracleConnection)dr.connect(DemoAESAndSHA1.URL,prop);
System.out.println("Connection created! Encryption algorithm is: " + oraConn.getEncryptionAlgorithmName() + ", data
integrity algorithm is: " + oraConn.getDataIntegrityAlgorithmName());
oraConn.close();
}

}

SSLのサポート

Oracle Database 11gでは、Secure Sockets Layer (SSL)プロトコルがサポートされています。SSLは広く使用されている業界標準のプロトコルで、セキュアなネットワーク通信を提供します。SSLは認証、データ暗号化およびデータ整合性を提供します。標準TCP/IPプロトコルのセキュリティ拡張で、インターネット通信に使用されます。

SSLでは、認証機能、および公開鍵/秘密鍵ペアによる暗号化の機能を提供するのに、X.509v3標準準拠のデジタル証明書が使用されます。SSLではまた、データのプライバシと整合性を保証するために、秘密鍵暗号化とデジタル署名も使用されます。SSLを介したネットワーク接続が開始されると、クライアントとサーバーでは次のようなステップを含むSSLハンドシェイクが実行されます。

- クライアントとサーバーとの間で、使用する暗号スイートを決めるためのネゴシエーションが行われます。これには、データ転送に使用する暗号化アルゴリズムの決定も含まれます。

- サーバーが自分の証明書をクライアントに送信し、クライアントは、その証明書が信頼できる認証機関(CA)によって署名されているかどうかを検証します。このステップにより、サーバーの身元が検証されます。

- クライアント認証が必要な場合は、クライアントが自分自身の証明書をサーバーに送信し、サーバーは、その証明書が信頼できるCAによって署名されているかどうかを検証します。

- クライアントとサーバーが、公開鍵暗号化を使用してキー情報を交換します。この情報に基づき、双方でセッション・キーが生成されます。クライアントとサーバーとの間の以降のやりとりはすべて、このセッション・キーのセットと、ネゴシエーションにより決定した暗号スイートを使用して、暗号化/復号化されます。

注意:
Oracle Database 11gリリース1(11.1)では、ThinドライバでSSL認証がサポートされています。このため、SSL認証を使用している場合、ユーザー名とパスワードのペアを指定する必要はありません。

SSLに関する用語

SSLのコンテキストでは、次の用語がよく使用されます。

- 証明書: 証明書とは、公開鍵とエンティティをバインドする、デジタル署名付きドキュメントのことです。証明書は、公開鍵が適切なエンティティに属していることを検証するために使用します。

- 認証機関: 認証機関(CA)は、デジタル署名付き証明書(他のエンティティによって使用される)を発行するエンティティです。認証局とも呼ばれます。

- 暗号スイート: 暗号スイートとは、SSL対応のネットワーク上で送信されるデータを暗号化するために使用される、暗号化アルゴリズムと鍵サイズのセットのことです。

- 秘密鍵: 秘密鍵は、ネットワークを介して伝送されることのない、文字どおり秘密の鍵です。秘密鍵は、対応する公開鍵を使用して暗号化されたメッセージを復号化するために使用されます。また、証明書に署名する際にも使用されます。その証明書を検証する際には、対応する公開鍵が使用されます。

- 公開鍵: 公開鍵とは、公開したり、電子メール・メッセージのような通常の手段で送信したりできる暗号化キーのことです。公開鍵は、SSL経由で送信されるメッセージを暗号化するために使用されます。また、対応する秘密鍵によって署名された証明書を検証する際にも使用されます。

- ウォレット: ウォレットとは、資格証明の認証や署名を格納するために使用される、パスワード保護付きのコンテナのことです。ウォレット内には、SSLで必要となる、秘密鍵、証明書、および信頼できる証明書が格納されます。

JavaバージョンのSSL

Java Secure Socket Extension(JSSE)は、SSLおよびTLSプロトコルのJavaバージョンを使用するためのフレームワークと実装を提供するものです。JSSEは、データの暗号化、サーバーとクライアントの認証、およびメッセージの整合性保持をサポートします。JSSEでは、アプリケーション開発者が直接アプリケーションに統合できる基礎要素が提供されるため、開発者は複雑なセキュリティ・アルゴリズムやハンドシェイク・メカニズムから解放され、アプリケーション開発が簡略化されます。JSSEは、Java Development Kit(JDK)1.4以上に統合され、SSLバージョン2.0と3.0をサポートします。

Oracle JDBCドライバでSSLを使用する前に、Sun社のJavaTM Secure Socket Extension(JSSE)フレームワークをよく理解しておくことをお薦めします。

JSSE標準のApplication Program Interface(API)は、javax.net、javax.net.sslおよびjavax.security.certの各パッケージで使用できます。これらのパッケージには、ソケット、サーバー・ソケット、SSLソケットおよびSSLサーバー・ソケットを作成および構成するためのクラスが用意されています。これらのパッケージには、セキュアなHTTP接続、JDK1.1ベースのプラットフォームと互換性がある公開鍵証明書API、および信頼のおける主要なマネージャ用のインタフェースも用意されています。

SSLは、Oracle Database 11gの環境においても、他のあらゆるネットワーク環境の場合と同様に機能します。この項の内容は次のとおりです。

- 証明書とウォレットの管理

- 鍵と証明書のコンテナ

証明書とウォレットの管理

Oracleデータベース・サーバーは、JDBCクライアント(ThinまたはOCI)とSSL接続を確立するために、ウォレットに格納されている自身の証明書を送信します。クライアントで証明書やウォレットが必要となるかどうかは、サーバーの構成によって決まります。

Oracle JDBC Thinドライバは、JSSEフレームワークを使用してSSL接続を作成します。デフォルトのプロバイダ(SunJSSE)を使用してSSLコンテキストを作成します。ただし、独自のプロバイダを指定できます。

サーバー上でSSL_CLIENT_AUTHENTICATIONパラメータが設定されていないかぎり、クライアント用の証明書は不要です。

鍵と証明書のコンテナ

Javaクライアントは、プロバイダさえあれば、Oracleウォレット、JKS、PKCS12など複数の種類のコンテナを使用することができます。Oracleウォレットの場合、SunJSSEプロバイダによって提供されるPKCS12サポートがPKCS12のすべての機能をサポートしているわけではないため、OraclePKIプロバイダを使用する必要があります。OraclePKIプロバイダを使用するには次のJARが必要です。

- oraclepki.jar

- osdt_cert.jar

- osdt_core.jar

これらすべてのJARファイルは$ORACLE_HOME/jlibディレクトリにあります。

Kerberosのサポート

Oracle Database 11gリリース1 (11.1)からKerberosサポートが導入されました。Kerberosはネットワーク経由で認証ツールと強固な暗号化ツールを提供するネットワーク認証プロトコルです。Kerberosは秘密鍵暗号化を使用する方式で、全社の情報システムのセキュリティ確保を容易に実現できます。Kerberosプロトコルは強固な暗号化を使用しているため、安全でないネットワーク接続を経由しても、クライアントまたはサーバーがサーバーまたはクライアントに対して身元を証明することができます。Kerberosを使用して身元を証明したクライアントおよびサーバーは、すべての通信を暗号化して、業務においてプライバシとデータ整合性を保全することができます。

Kerberosアーキテクチャは鍵配布センター(KDC)と呼ばれる信頼できる認証サービスを軸としています。Kerberos環境のユーザーおよびサービスはプリンシパルと呼ばれ、各プリンシパルはKDCと秘密鍵(パスワードなど)を共有します。プリンシパルはscottなどのユーザーの場合も、データベース・サーバーのインスタンスの場合もあります。

Kerberosを使用するためのWindowsの構成

klist、kinitなどのツールを提供する良質なKerberosクライアントは、次のリンクの場所にあります。

http://web.mit.edu/kerberos/dist/index.html

このクライアントでは便利なGUIも提供しています。

WindowsマシンでKerberosを構成するには、次の変更を行う必要があります。

1. デスクトップで「マイ コンピュータ」アイコンを右クリックします。

2. 「プロパティ」を選択します。「システムのプロパティ」ダイアログ・ボックスが表示されます。

3. 「詳細設定」タブを選択します。

4. 「環境変数」をクリックします。「環境変数」ダイアログ・ボックスが表示されます。

5. 「新規」をクリックして新しい利用者変数を追加します。「新しいユーザー変数」ダイアログ・ボックスが表示されます。

6. 「変数名」フィールドに「KRB5CCNAME」と入力します。

7. 「変数値」フィールドに「FILE:C:\Documents and Settings\<user_name>\krb5cc」と入力します。

8. 「OK」をクリックして「新しいユーザー変数」ダイアログ・ボックスを閉じます。

9. 「OK」をクリックして「環境変数」ダイアログ・ボックスを閉じます。

10. 「OK」をクリックして「システムのプロパティ」ダイアログ・ボックスを閉じます。

注意:
C:\WINDOWS\krb5.iniファイルは、krb5.confファイルと内容が同じです。

Kerberosを使用するためのOracle Databaseの構成

Kerberosを使用するには、次の手順でOracle Databaseを構成します。

1. 次のコマンドを使用してデータベースに接続します。

SQL> connect system
Enter password: password

2. 次のコマンドを使用して、外部で身元が保証されたユーザーCLIENT@US.ORACLE.COMを作成します。

SQL> create user "CLIENT@US.ORACLE.COM" identified externally;
SQL> grant create session to "CLIENT@US.ORACLE.COM";

3. 次のコマンドを使用して、sysdbaとしてデータベースに接続し、ディスマウントします。

SQL> connect / as sysdba
SQL> shutdown immediate;

4. $T_WORK/t_init1.oraファイルに次の行を追加します。

OS_AUTHENT_PREFIX=""

5. 次のコマンドを使用してデータベースを再起動します。

SQL> startup pfile=t_init1.ora

6. sqlnet.oraファイルを編集して次の行を入れます。

names.directory_path = (tnsnames)
#Kerberos
sqlnet.authentication_services = (beq,kerberos5)
sqlnet.authentication_kerberos5_service = dbji
sqlnet.kerberos5_conf = /home/Jdbc/Security/kerberos/krb5.conf
sqlnet.kerberos5_keytab = /home/Jdbc/Security/kerberos/dbji.oracleserver
sqlnet.kerberos5_conf_mit = true
sqlnet.kerberos_cc_name = /tmp/krb5cc_5088
# logging (optional):
trace_level_server=16
trace_directory_server=/scratch/sqlnet/

7. 次のコマンドを使用して、SQL*Plusを経由して接続できることを確認します。

> kinit client
> klist
Ticket cache: FILE:/tmp/krb5cc_5088
Default principal: client@US.ORACLE.COM

Valid starting     Expires            Service principal
06/22/06 07:13:29  06/22/06 17:13:29  krbtgt/US.ORACLE.COM@US.ORACLE.COM

Kerberos 4 ticket cache: /tmp/tkt5088
klist: You have no tickets cached
> sqlplus '/@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracleserver.mydomain.com)(PORT=5529))
(CONNECT_DATA=(SERVICE_NAME=mydatabaseinstance)))'

注意:
Kerberosの使用方法については、次のWebサイトを参照してください。

http://www.microsoft.com/windowsserver2003/technologies/security/kerberos/default.mspx
http://redhatpartnerweb.com/docs/manuals/linux/RHL-7.3-Manual/ref-guide/s1-kerberos-server.html

サンプル・コード

次の例は、Oracle Database 11gリリース2(11.2)のJDBC Thinドライバに含まれている新しいKerberos認証機能を示しています。このデモは、次の2つの使用例を説明しています。

- 最初のシナリオでは、OSがユーザー名と資格証明をメンテナンスします。資格証明はキャッシュに格納され、ドライバは資格証明を取得してからサーバーの認証を受けようとします。この使用例はモジュールconnectWithDefaultUser()にあります。

注意:

1. デモのこの部分を実行する前に、次のコマンドを使用して、有効な資格証明を持っていることを確認してください。

> /usr/kerberos/bin/kinit client
where, the password is welcome.

2. 次のコマンドを使用してチケットをリストします。

> /usr/kerberos/bin/klist

- 2番目の使用例は、アプリケーションがユーザーの資格証明を制御する事例です。これは、複数のWebユーザーが各自の資格証明を持っているアプリケーション・サーバーの場合です。この使用例はモジュールconnectWithSpecificUser()にあります。

注意:
このデモを実行するには、作業用の設定として、稼働中のKerberosサーバーと、Kerberos認証を使用するように構成されているOracleデータベース・サーバーが必要です。例をコンパイルして実行するには、使用されているURLを変更する必要があります。

例9-4 Kerberos認証を使用したデータベースへの接続

import com.sun.security.auth.module.Krb5LoginModule;
import java.io.IOException;

import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import java.util.HashMap;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;

import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.net.ano.AnoServices;
public class KerberosJdbcDemo
{
String url ="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)"+
"(HOST=oracleserver.mydomain.com)(PORT=5561))(CONNECT_DATA=" +
"(SERVICE_NAME=mydatabaseinstance)))";

public static void main(String[] arv)
{
/* If you see the following error message [Mechanism level: Could not load
* configuration file c:\winnt\krb5.ini (The system cannot find the path
* specified] it's because the JVM cannot locate your kerberos config file.
* You have to provide the location of the file. For example, on Windows,
* the MIT Kerberos client uses the config file: C\WINDOWS\krb5.ini:
*/
// System.setProperty("java.security.krb5.conf","C:\\WINDOWS\\krb5.ini");
System.setProperty("java.security.krb5.conf","/home/Jdbc/Security/kerberos/krb5.conf");

KerberosJdbcDemo kerberosDemo = new KerberosJdbcDemo();
try
{
System.out.println("Attempt to connect with the default user:");
kerberosDemo.connectWithDefaultUser();
}
catch (Exception e)
{
e.printStackTrace();
}
try
{
System.out.println("Attempt to connect with a specific user:");
kerberosDemo.connectWithSpecificUser();
}
catch (Exception e)
{
e.printStackTrace();
}
}

void connectWithDefaultUser() throws SQLException
{
OracleDriver driver = new OracleDriver();
Properties prop = new Properties();

prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERVICES,
"("+AnoServices.AUTHENTICATION_KERBEROS5+")");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_MUTUAL,
"true");

/* If you get the following error [Unable to obtain Princpal Name for
* authentication] although you know that you have the right TGT in your
* credential cache, then it's probably because the JVM can't locate your
* cache.
*
* Note that the default location on windows is "C:\Documents and Settings\krb5cc_username".
*/

// prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_CC_NAME,
/*
On linux:
> which kinit
/usr/kerberos/bin/kinit
> ls -l /etc/krb5.conf
lrwxrwxrwx    1 root  root   47 Jun 22 06:56 /etc/krb5.conf -> /home/Jdbc/Security/kerberos/krb5.conf

> kinit client
Password for client@US.ORACLE.COM:
> klist
Ticket cache: FILE:/tmp/krb5cc_5088
Default principal: client@US.ORACLE.COM

Valid starting     Expires            Service principal
11/02/06 09:25:11  11/02/06 19:25:11  krbtgt/US.ORACLE.COM@US.ORACLE.COM

Kerberos 4 ticket cache: /tmp/tkt5088
klist: You have no tickets cached
*/
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_CC_NAME,
"/tmp/krb5cc_5088");
Connection conn  = driver.connect(url,prop);
String auth = ((OracleConnection)conn).getAuthenticationAdaptorName();
System.out.println("Authentication adaptor="+auth);
printUserName(conn);
conn.close();
}

void connectWithSpecificUser() throws Exception
{
Subject specificSubject = new Subject();

// This first part isn't really meaningful to the sake of this demo. In
// a real world scenario, you have a valid "specificSubject" Subject that
// represents a web user that has valid Kerberos credentials.
Krb5LoginModule krb5Module = new Krb5LoginModule();
HashMap sharedState = new HashMap();
HashMap options = new HashMap();
options.put("doNotPrompt","false");
options.put("useTicketCache","false");
options.put("principal","client@US.ORACLE.COM");

krb5Module.initialize(specificSubject,newKrbCallbackHandler(),sharedState,options);
boolean retLogin = krb5Module.login();
krb5Module.commit();
if(!retLogin)
throw new Exception("Kerberos5 adaptor couldn't retrieve credentials (TGT) from the cache");

// to use the TGT from the cache:
// options.put("useTicketCache","true");
// options.put("doNotPrompt","true");
// options.put("ticketCache","C:\\Documents and Settings\\user\\krb5cc");
// krb5Module.initialize(specificSubject,null,sharedState,options);

// Now we have a valid Subject with Kerberos credentials. The second scenario
// really starts here:
// execute driver.connect(...) on behalf of the Subject 'specificSubject':
Connection conn =
(Connection)Subject.doAs(specificSubject, new PrivilegedExceptionAction()
{
public Object run()
{
Connection con = null;
Properties prop = new Properties();
prop.setProperty(AnoServices.AUTHENTICATION_PROPERTY_SERVICES,
"(" + AnoServices.AUTHENTICATION_KERBEROS5 + ")");
try
{
OracleDriver driver = new OracleDriver();
con = driver.connect(url, prop);

} catch (Exception except)
{
except.printStackTrace();
}
return con;
}
});

String auth = ((OracleConnection)conn).getAuthenticationAdaptorName();
System.out.println("Authentication adaptor="+auth);
printUserName(conn);
conn.close();
}

void printUserName(Connection conn) throws SQLException
{
Statement stmt = null;
try
{
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select user from dual");
while(rs.next())
System.out.println("User is:"+rs.getString(1));
rs.close();
}
finally
{
if(stmt != null)
stmt.close();
}
}
}

class KrbCallbackHandler implements CallbackHandler
{
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException
{
for (int i = 0; i < callbacks.length; i++)
{
if (callbacks[i] instanceof PasswordCallback)
{
PasswordCallback pc = (PasswordCallback)callbacks[i];
System.out.println("set password to 'welcome'");
pc.setPassword((new String("welcome")).toCharArray());
} else
{
throw new UnsupportedCallbackException(callbacks[i],
"Unrecognized Callback");
}
}
}
}

RADIUSのサポート

Oracle Database 11gリリース1(11.1)から、リモート認証ダイアルイン・ユーザー・サービス(RADIUS)が導入されました。RADIUSは、最も広く知られている、リモートでの認証とアクセスを可能にするクライアント/サーバー・セキュリティ・プロトコルです。Oracle Advanced Securityは、この標準をクライアント/サーバー・ネットワーク環境で使用して、RADIUSプロトコルをサポートするあらゆる認証方式の使用を可能にします。RADIUSは、トークン・カードやスマート・カードなど、いろいろな認証メカニズムで使用できます。この項の内容は次のとおりです。

- RADIUSを使用するためのOracle Databaseの構成

- サンプル・コード

RADIUSを使用するためのOracle Databaseの構成

RADIUSを使用するには、次の手順でOracle Databaseを構成します。

1. 次のコマンドを使用してデータベースに接続します。

SQL> connect system
Enter password: password

2. 次のコマンドを使用して、データベース内から新規ユーザーasoを作成します。

SQL> create user aso identified externally;
SQL> grant create session to aso;

3. 次のコマンドを使用して、sysdbaとしてデータベースに接続し、ディスマウントします。

SQL> connect / as sysdba
SQL> shutdown immediate;

4. t_init1.oraファイルに次の行を追加します。

os_authent_prefix = ""

注意:
テストが終了したら、t_init1.oraファイルに加えられたこれまでの変更を元に戻す必要があります。

5. 次のコマンドを使用してデータベースを再起動します。

SQL> startup pfile=?/work/t_init1.ora

6. 次の行のみが含まれるようにsqlnet.oraファイルを変更します。

sqlnet.authentication_services = ( beq, radius)
sqlnet.radius_authentication = <RADUIUS_SERVER_HOST_NAME>
sqlnet.radius_authentication_port = 1812
sqlnet.radius_authentication_timeout = 120
sqlnet.radius_secret=/home/Jdbc/Security/radius/radius_key
# logging (optional):
trace_level_server=16
trace_directory_server=/scratch/sqlnet/

7. 次のコマンドを使用して、SQL*Plusを経由して接続できることを確認します。

>sqlplus 'aso/1234@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracleserver.mydomain.com)(PORT=5529))
(CONNECT_DATA=(SERVICE_NAME=mydatabaseinstance)))'

サンプル・コード

この例は、Oracle Database 11gリリース2(11.2)のJDBC Thinドライバに含まれている新しいRADIUS認証機能を示しています。作業用の設定として、稼働中のKerberosサーバーと、Kerberos認証を使用するように構成されているOracleデータベース・サーバーが必要です。例をコンパイルして実行するには、指定されているURLを変更する必要があります。

例9-5 RADIUS認証を使用したデータベースへの接続

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.net.ano.AnoServices;
public class RadiusJdbcDemo
{
String url ="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)"+
"(HOST=oracleserver.mydomain.com)(PORT=5561))(CONNECT_DATA=" +
"(SERVICE_NAME=mydatabaseinstance)))";

public static void main(String[] arv)
{
RadiusJdbcDemo radiusDemo = new RadiusJdbcDemo();
try
{
radiusDemo.connect();
}
catch (Exception e)
{
e.printStackTrace();
}
}

/*
* This method attempts to logon to the database using the RADIUS
* authentication protocol.
*
* It should print the following output to stdout:
* -----------------------------------------------------
* Authentication adaptor=RADIUS
* User is:ASO
* -----------------------------------------------------
*/
void connect() throws SQLException
{
OracleDriver driver = new OracleDriver();
Properties prop = new Properties();

prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERVICES,
"("+AnoServices.AUTHENTICATION_RADIUS+")");
// The user "aso" needs to be properly setup on the radius server with
// password "1234".
prop.setProperty("user","aso");
prop.setProperty("password","1234");

Connection conn  = driver.connect(url,prop);
String auth = ((OracleConnection)conn).getAuthenticationAdaptorName();
System.out.println("Authentication adaptor="+auth);
printUserName(conn);
conn.close();
}

void printUserName(Connection conn) throws SQLException
{
Statement stmt = null;
try
{
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select user from dual");
while(rs.next())
System.out.println("User is:"+rs.getString(1));
rs.close();
}
finally
{
if(stmt != null)
stmt.close();
}
}
}

セキュアな外部パスワード記憶域

アプリケーションがパスワード資格証明を使用してデータベースに接続する大規模なデプロイメントでの代替として、クライアント側のOracle Walletにそれらの資格証明を格納できます。Oracle Walletは、資格証明の認証および署名の格納に使用されるセキュアなソフトウェア・コンテナです。

クライアント側のOracleウォレットにデータベースのパスワード資格証明を格納すると、アプリケーション・コードやバッチ・ジョブ、スクリプトにユーザー名とパスワードを埋め込む必要がなくなります。このため、スクリプトやアプリケーション・コード内にパスワードが露出する危険性が減少し、ユーザー名やパスワードを変更するたびにコードを変更する必要がなくなるため、管理が単純化されます。また、アプリケーション・コードを変更する必要がないため、これらのユーザー・アカウントに対してパスワード管理ポリシーをさらに簡単に強制適用できるようになります。

oracle.net.wallet_location接続プロパティを設定して、ウォレットの場所を指定できます。JDBCドライバは、このウォレットからユーザー名とパスワードのペアを取得できます。

関連項目:
セキュアな外部パスワード記憶域を使用するようにクライアントを構成する方法、およびその記憶域で資格証明を管理する方法については、『Oracle Database Advanced Security管理者ガイド』を参照してください。

10 プロキシ認証

Oracle Java Database Connectivity(JDBC)は、n層認証とも呼ばれるプロキシ認証を提供しています。この機能は、JDBC Oracle Call Interface(OCI)ドライバとJDBC Thinドライバの両方を介してサポートされています。この章の内容は次のとおりです。

- プロキシ認証について

- 各種のプロキシ接続

- プロキシ接続の作成

- プロキシ・セッションのクローズ

- プロキシ接続のキャッシュ

- プロキシ接続の制限

注意:
Oracle Databaseはプロキシ認証機能を3つの層のみでサポートしています。複数の中間層を横断してのサポートはありません。

プロキシ認証について

プロキシ認証はユーザー認証に中間層を使用する処理です。次の3つの形式のプロキシ認証を使用することによって、クライアントのセキュアなプロキシとして動作する中間層サーバーを設計することができます。

- 中間層サーバーはデータベース・サーバーおよびクライアントに対してそれ自身を認証します。この場合、アプリケーション・ユーザーまたは別のアプリケーションは中間層サーバーに対して自分自身を認証します。クライアントのIDはデータベースまですべての段階で維持されています。

- クライアント、つまりデータベース・ユーザーは、中間層サーバーによっては認証されません。クライアントのIDとデータベース・パスワードは、中間層サーバーを経由してデータベース・サーバーに渡され、認証に使用されます。

- クライアント、つまりグローバル・ユーザーは中間層サーバーによって認証され、クライアントのユーザー名を取得するために中間層を経由して識別名(DN)または証明書を渡します。

注意:
中間層サーバーがクライアントの代理として行った処理は監査できます。詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

関連項目:
「プロキシ接続の作成」

すべての場合で、クライアントのプロキシ(代理)として動作するために、管理者は中間層サーバーを認証する必要があります。たとえば、中間層サーバーが最初にユーザーscottとしてデータベースに接続し、プロキシ接続をユーザーjeffとしてアクティブにしてから、次の文を発行して、クライアントのプロキシとして動作するように中間層サーバーを認証するとします。

ALTER USER jeff GRANT CONNECT THROUGH scott;

また、次のことも可能です。

- クライアントとして接続する場合に中間層がアクティブにすることを許可されるロールを指定すること。たとえば、次のようになります。

CREATE ROLE role1;
GRANT SELECT ON emp TO role1;
ALTER USER jeff GRANT CONNECT THROUGH scott ROLE role1;

このrole句は、ロール・リストに指定されたデータベース・オブジェクトのみにアクセスを制限します。空のロール・リストを指定することも可能です。

- PROXY_USERSデータ・ディクショナリ・ビューに問い合せて、中間層への接続を現在認可されているユーザーを検索すること。

- ALTER USER文のREVOKE CONNECT THROUGH句を使用してプロキシ接続の認可を取り消すこと。

注意:
この章では、データベースへのJDBC接続はデータベース内のユーザー・セッションであり、その逆の場合もあります。

各種のプロキシ接続を設定するには、oracle.jdbc.OracleConnectionインタフェースにある、各種のフィールドやメソッドを使用する必要があります。

各種のプロキシ接続

プロキシ接続は、次のいずれかのオプションを使用して作成できます。

- USER NAME
このオプションは、ユーザー名またはパスワード(あるいはその両方)を指定して実行します。パスワードを使用する認証を指定するには、次のSQL文を使用します。

ALTER USER jeff GRANT CONNECT THROUGH scott AUTHENTICATED USING password;

この場合、jeffはユーザー名で、scottはjeffのプロキシです。

パスワード・オプションは、セキュリティを強化するためのものです。authenticated句がない場合、パスワードがなく、ユーザー名のみを使用するデフォルトの認証が使用されます。デフォルト認証を指定するには、次のSQL文を使用します。

ALTER USER jeff GRANT CONNECT THROUGH scott

- DISTINGUISHED NAME
これは、プロキシとしての役割を果すユーザーのパスワードにかわるグローバル名です。識別名を使用する場合のSQL文の例を次に示します。

CREATE USER jeff IDENTIFIED GLOBALLY AS 'CN=jeff,OU=americas,O=oracle,L=redwoodshores,ST=ca,C=us';

identified globally as句の後に続く文字列が識別名です。次に、この識別名を使用して認証する必要があります。識別名を使用して認証を指定するには、次のSQL文を使用します。

ALTER USER jeff GRANT CONNECT THROUGH scott AUTHENTICATED USING DISTINGUISHED NAME;

- CERTIFICATE
これは、プロキシとしての役割を果すユーザーの資格証明をさらに暗号化してデータベースに渡す方法です。証明書には、エンコードされた識別名が含まれています。証明書を生成する1つの方法は、ウォレットを作成してから、そのウォレットをデコード化して証明書を取得することです。ウォレットはrunutl mkwalletを使用して作成できます。次に、生成された証明書を使用して認証する必要があります。証明書を使用する認証を指定するには、次のSQL文を使用します。

ALTER USER jeff GRANT CONNECT THROUGH scott AUTHENTICATED USING CERTIFICATE;

注意:
証明書によるプロキシ認証は、将来のOracle Databaseリリースではサポート対象外となります。

注意:

- すべてのオプションは、ロールと関連付けることができます。

- プロキシとしての役割を果す新しい接続をオープンすると、新しいセッションがデータベース・サーバー上で開始されます。このセッションとともに、新しいローカル・トランザクションが作成されます。

プロキシ接続の作成

ユーザー(たとえば、jeff)は、別のユーザー(たとえば、scott)を介してデータベースに接続する必要があります。プロキシ・ユーザーscottには、アクティブな認証済接続が必要です。ドライバがサーバーにコマンドを送信してユーザーjeffのセッションを作成することで、このアクティブな接続上にプロキシ・セッションが作成されます。サーバーは新しいセッションIDを戻し、ドライバはセッション切替えコマンドを送信してこの新しいセッションに切り替えます。

JDBC OCIとThinドライバは、同じ方法でセッションを切り替えます。ドライバは、永続的に新しいセッションjeffに切り替えます。その結果、プロキシ・セッションscottは、新しいセッションjeffがクローズされるまで使用できません。

注意:
oracle.jdbc.OracleConnectionインタフェースからisProxySessionメソッドを使用して、接続に関連付けられている現在のセッションがプロキシ・セッションであるかどうかをチェックすることができます。接続に関連付けられている現在のセッションがプロキシ・セッションの場合、このメソッドはtrueを戻します。

oracle.jdbc.OracleConnectionインタフェースから、次のメソッドを使用することで、新しいプロキシ・セッションが開かれます。

void openProxySession(int type, java.util.Properties prop) throws SQLExceptionOpens

ここで、

typeはプロキシ・セッションのタイプで、次の値を指定できます。

- OracleConnection.PROXYTYPE_USER_NAME
このタイプのセッションは、ユーザー名を指定するために使用されます。

- OracleConnection.PROXYTYPE_DISTINGUISHED_NAME
このタイプのセッションは、ユーザーの識別名を指定するために使用されます。

- OracleConnection.PROXYTYPE_CERTIFICATE
このタイプのセッションは、プロキシ証明書を指定するために使用されます。

propはプロキシ・セッションのプロパティ値で、次の値を指定できます。

- PROXY_USER_NAME
このプロパティ値はタイプOracleConnection.PROXYTYPE_USER_NAMEで使用できます。値はjava.lang.Stringになります。

- PROXY_DISTINGUISHED_NAME
このプロパティ値はタイプOracleConnection.PROXYTYPE_DISTINGUISHED_NAMEで使用できます。値はjava.lang.Stringになります。

- PROXY_CERTIFICATE
このプロパティ値はタイプOracleConnection.PROXYTYPE_CERTIFICATEで使用できます。値は、証明書が含まれるbytep[]配列です。

- PROXY_ROLES
このプロパティ値は次のタイプで使用できます。

- OracleConnection.PROXYTYPE_USER_NAME

- OracleConnection.PROXYTYPE_DISTINGUISHED_NAME

- OracleConnection.PROXYTYPE_CERTIFICATE

値はjava.lang.Stringになります。

- PROXY_SESSION
このプロパティ値は、プロキシ・セッションを閉じるためにcloseメソッドで使用されます。

関連項目:
「プロキシ・セッションのクローズ」

- PROXY_USER_PASSWORD
このプロパティ値はタイプOracleConnection.PROXYTYPE_USER_NAMEで使用できます。値はjava.lang.Stringになります。

次のコードは、openProxySessionメソッドの使用方法を示します。

java.util.Properties prop = new java.util.Properties();
prop.put(OracleConnection.PROXY_USER_NAME, "jeff");
String[] roles = {"role1", "role2"};
prop.put(OracleConnection.PROXY_ROLES, roles);
conn.openProxySession(OracleConnection.PROXYTYPE_USER_NAME, prop);

プロキシ・セッションのクローズ

OracleConnection.closeメソッドにOracleConnection.PROXY_SESSIONパラメータを渡すことによって、OracleConnection.openProxySessionメソッドでオープンしたプロキシ・セッションをクローズするには、次の操作を行います。

OracleConnection.close(OracleConnection.PROXY_SESSION);

これは、キャッシュされていない接続でのプロキシ・セッションのクローズと同じです。接続自体をクローズするには、標準のcloseメソッドを明示的にコールする必要があります。プロキシ・セッションをクローズせずにcloseメソッドを直接コールすると、プロキシ・セッションと接続の両方がクローズします。その方法は次のとおりです。

OracleConnection.close(OracleConnection.INVALID_CONNECTION);

関連項目:
第21章「暗黙的接続キャッシュ」

プロキシ接続のキャッシュ

プロキシ接続は、通常の接続と同様にキャッシュできます。プロキシ接続をキャッシュすると、パフォーマンスが向上します。プロキシ接続をキャッシュするには、getConnectionメソッドのいずれかを使用して、キャッシュ対応のOracleDataSourceオブジェクトで接続を作成する必要があります。

関連項目:
第21章「暗黙的接続キャッシュ」

プロキシ接続は、接続キャッシュの接続属性機能を使用して、接続キャッシュ内にキャッシュできます。接続属性はユーザー定義の名前/値ペアで、接続を接続キャッシュに戻して再利用する前に接続にタグを付けるのに役立ちます。タグ付けされた接続が取得されると、その接続を直接使用してプロキシ・セッションを作成またはクローズできるため、ラウンドトリップは必要ありません。暗黙的接続キャッシュは、すべてのユーザー/パスワード認証接続のキャッシュをサポートします。したがって、ユーザー認証のすべてのプロキシ接続はキャッシュおよび取得できます。

接続属性を適用せずにプロキシ接続をクローズすることはお薦めしません。接続属性を適用せずにプロキシ接続をクローズすると、その接続は再利用のために接続キャッシュに戻されますが取得できません。接続キャッシュ・メカニズムでは、セッション状態を記憶したりリセットしたりしません。

プロキシ接続は、直接クローズすることで、接続キャッシュから削除できます。

関連項目:
「プロキシ・セッションのクローズ」

プロキシ接続の制限

プロキシ接続をクローズすると、プロキシ・セッション中またはプロキシ・セッションより前にプロキシ接続によって作成されたすべてのSQL文が自動的にクローズされます。これがアプリケーション・プーリングまたは文キャッシュに予期しない結果を招く可能性があります。次のサンプル・コードは、プロキシ接続のこの制限について説明しています。

例1

....
public void displayName(String N)  // Any function using the Proxy feature
{
Properties props = new Properties();
props.put("PROXY_USER_NAME", proxyUser);
c.openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);
.......
c.close(OracleConnection.PROXY_SESSION);
}

public static void main (String args[]) throws SQLException
{
............
PreparedStatement pstmt = conn.prepareStatement("SELECT empname FROM EMP WHERE empno = ?");
pstmt.setString(1, "28959");
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
displayName(rs.getString(1));
if (rs.isClosed() // The ResultSet is already closed while closing the connection!
{
throw new Exception("Your ResultSet has been prematurely closed!
Your Statement object is also dead now.");
}
}
}

この例では、displayNameメソッドでプロキシ接続をクローズすると、PreparedStatementオブジェクトとResultSetオブジェクトもクローズされます。したがって、ループ内でResultSetオブジェクトのステータスをチェックしないと、そのループはnextメソッドが2度目にコールされたときに失敗します。

例2

....
PreparedStatement pstmt = conn.prepareStatement("SELECT empname FROM EMP WHERE empno = ?");
pstmt.setString(1, "28959");
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
....
}

Properties props = new Properties();
props.put("PROXY_USER_NAME", proxyUser);

conn.openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);
.......
conn.close(OracleConnection.PROXY_SESSION);

// Try to use the PreparedStatement again
pstmt.setString(1, "28960");
// This line of code will fail because the Statement is already closed while closing the connection!
rs = pstmt.executeQuery();

この例では、PreparedStatementオブジェクトとResultSetオブジェクトは、プロキシ接続をオープンする前はうまく機能します。しかし、同じPreparedStatementオブジェクトをプロキシ接続のクローズ後に実行しようとすると、その文は失敗します。

第IV部

データへのアクセスと操作

第IV部では、Oracleデータへのアクセスと操作について説明します。また、ユーザー定義のオブジェクト型、ラージ・オブジェクト(LOB)とバイナリ・ファイル(BFILE)のロケータとデータ、オブジェクト参照およびOracleコレクション(ネストした表など)に対するJava Database Connectivity(JDBC)サポートについて説明します。さらに、JDBCでの結果セット機能、JDBC RowSet、およびJDBCドライバによって提供されるグローバリゼーション・サポートについても説明します。

第IV部の構成は次のとおりです。

- 第11章「Oracleデータへのアクセスと操作」

- 第12章「JDBC内のJavaストリーム」

- 第13章「Oracleオブジェクト型の操作」

- 第14章「LOBとBFILEの操作」

- 第15章「Oracleオブジェクト参照の使用」

- 第16章「Oracleコレクションの操作」

- 第17章「結果セット」

- 第18章「JDBC RowSet」

- 第19章「グローバリゼーション・サポート」

このページのスクリプト内容はナビゲーション目的にのみ使用され、内容を変更するものではありません。

11 Oracleデータへのアクセスと操作

この章では、oracle.sql.*形式でのデータ・アクセスについて、標準Java形式と対比させて説明します。oracle.sql.*形式を使用するには、結果セットと文を適宜OracleResultSet、OracleStatement、OraclePreparedStatementおよびOracleCallableStatementにキャストし、これらのクラスのgetOracleObject、setOracleObject、getXXXおよびsetXXXメソッド(XXXはoracle.sqlパッケージの型に対応)を使用する必要があります。

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

- データ型マッピング

- データ変換での考慮事項

- 結果セットと文拡張機能

- Oracleのgetおよびsetメソッドと標準JDBCの比較

- 結果セット・メタデータ拡張機能の使用方法

- SQL CALL文とCALL INTO文の使用

データ型マッピング

Oracle JDBCドライバは、Oracle固有のデータ型に加えて、標準JDBC型をサポートしています。この項では、標準およびOracle固有のSQL-Javaデフォルト型マッピングについて説明します。この項の内容は次のとおりです。

- マッピングの表

- マッピングに関する注意

マッピングの表

表11-1は、SQLデータ型、JDBC型コード、標準Java型およびOracle拡張型間のデフォルト・マッピングを示しています。

SQLデータ型の列は、Oracle Database 11gに存在するSQL型を示しています。JDBC型コードの列は、JDBC標準によってサポートされ、java.sql.Typesクラス、またはoracle.jdbc.OracleTypesクラスでOracleによって定義されるデータの型コードを示しています。標準の型コードの場合、コードはこの2つのクラスで同一です。

標準Java型の列は、Java言語で定義される標準型を示しています。Oracle拡張機能Java型の列は、データベース内の各SQLデータ型に対応したoracle.sql.*Java型を示しています。これらは、oracle.sql.* Java型でSQLデータすべての取出しを可能にするOracle拡張機能です。

注意:

- 一般に、Oracle JDBCドライバは、標準JDBC型を使用してSQLデータを操作するように最適化されています。いくつかの特殊な例では、oracle.sqlパッケージで入手できるOracle拡張クラスを使用するのが有利な場合があります。しかし、できるかぎりOracle拡張機能ではなく標準JDBC型を使用することを強くお薦めします。Oracle拡張機能を使用すべき場合の詳細は、「標準型とOracle型」を参照してください。

- Oracle JDBCドライバは、複数の接続によるJDBC型の共有をサポートしていません。

関連項目:
Oracle拡張機能の詳細は、「パッケージoracle.sql」を参照してください。

表11-1 SQL型とJava型間のデフォルト・マッピング

SQLデータ型

JDBC型コード

標準Java型

Oracle拡張機能Java型

標準JDBC型:

CHAR

java.sql.Types.CHAR

java.lang.String

oracle.sql.CHAR

VARCHAR2

java.sql.Types.VARCHAR

java.lang.String

oracle.sql.CHAR

LONG

java.sql.Types.LONGVARCHAR

java.lang.String

oracle.sql.CHAR

NUMBER

java.sql.Types.NUMERIC

java.math.BigDecimal

oracle.sql.NUMBER

NUMBER

java.sql.Types.DECIMAL

java.math.BigDecimal

oracle.sql.NUMBER

NUMBER

java.sql.Types.BIT

boolean

oracle.sql.NUMBER

NUMBER

java.sql.Types.TINYINT

byte

oracle.sql.NUMBER

NUMBER

java.sql.Types.SMALLINT

short

oracle.sql.NUMBER

NUMBER

java.sql.Types.INTEGER

int

oracle.sql.NUMBER

NUMBER

java.sql.Types.BIGINT

long

oracle.sql.NUMBER

NUMBER

java.sql.Types.REAL

float

oracle.sql.NUMBER

NUMBER

java.sql.Types.FLOAT

double

oracle.sql.NUMBER

NUMBER

java.sql.Types.DOUBLE

double

oracle.sql.NUMBER

RAW

java.sql.Types.BINARY

byte[]

oracle.sql.RAW

RAW

java.sql.Types.VARBINARY

byte[]

oracle.sql.RAW

LONGRAW

java.sql.Types.LONGVARBINARY

byte[]

oracle.sql.RAW

DATE

java.sql.Types.DATE

java.sql.Date

oracle.sql.DATE

DATE

java.sql.Types.TIME

java.sql.Time

oracle.sql.DATE

TIMESTAMP

java.sql.Types.TIMESTAMP

javal.sql.Timestamp

oracle.sql.TIMESTAMP

BLOB

java.sql.Types.BLOB

java.sql.Blob

oracle.sql.BLOB

CLOB

java.sql.Types.CLOB

java.sql.Clob

oracle.sql.CLOB

ユーザー定義オブジェクト

java.sql.Types.STRUCT

java.sql.Struct

oracle.sql.STRUCT

ユーザー定義参照

java.sql.Types.REF

java.sql.Ref

oracle.sql.REF

ユーザー定義コレクション

java.sql.Types.ARRAY

java.sql.Array

oracle.sql.ARRAY

ROWID

java.sql.Types.ROWID

java.sql.RowId

oracle.sql.ROWID

NCLOB

java.sql.Types.NCLOB

java.sql.NClob

oracle.sql.NCLOB

NCHAR

java.sql.Types.NCHAR

java.lang.String

oracle.sql.CHAR

Oracle拡張機能:

BFILE

oracle.jdbc.OracleTypes.BFILE

N/A

oracle.sql.BFILE

REF CURSOR

oracle.jdbc.OracleTypes.CURSOR

java.sql.ResultSet

oracle.jdbc.OracleResultSet

TIMESTAMP

oracle.jdbc.OracleTypes.TIMESTAMP

java.sql.Timestamp

oracle.sql.TIMESTAMP

TIMESTAMPWITHTIMEZONE

oracle.jdbc.OracleTypes.TIMESTAMPLTZ

java.sql.Timestamp

oracle.sql.TIMESTAMPLTZ

TIMESTAMPWITHLOCALTIMEZONE

oracle.jdbc.OracleTypes.TIMESTAMPLTZ

java.sql.Timestamp

oracle.sql.TIMESTAMPLTZ

注意:
バージョン8.1.7など、TIMESTAMPデータ型をサポートしていないデータベースのバージョンの場合、TIMESTAMPはDATEにマップされます。

関連項目:

- 「有効なSQL-JDBCデータ型マッピング」

- 第4章「Oracle拡張機能」

マッピングに関する注意

この項では、NUMBERおよびユーザー定義型のマッピングに関する詳細を提供します。

NUMBER型

Oracle NUMBER値が対応できる様々な型コードでは、マッピングを正しく動作させるために、データのサイズに適切なgetterルーチンをコールします。たとえば、-128 < x < 128の項目xに対してJava tinyint値を取得するには、getByteをコールします。

ユーザー定義型

オブジェクト、オブジェクト参照およびコレクションなどのユーザー定義型は、デフォルトでjava.sql.Structなどの弱いJava型にマップされますが、かわりに強い型指定のカスタムJavaクラスにもマップできます。カスタムJavaクラスは、次のいずれかのインタフェースを実装できます。

- 標準java.sql.SQLData

- Oracle固有oracle.sql.ORAData

関連項目:
「Oracleオブジェクトのマッピング」および「Oracleオブジェクト用のカスタム・オブジェクト・クラスの作成と使用方法」

データ変換での考慮事項

JDBCプログラムでSQLデータをJavaに取り込む場合は、標準Java型またはoracle.sqlパッケージの型を使用できます。この項の内容は次のとおりです。

- 標準型とOracle型

- SQL NULLデータの変換

- NULLのテスト

標準型とOracle型

oracle.sqlのOracleデータ型では、データベースで使用されているのと同じビット形式でデータが格納されます。Oracle Database 10gより前のバージョンのOracle JDBCドライバでは、通常、Oracleデータ型の方が効率的でした。Oracle Database 10g JDBCドライバは大幅に更新されました。その結果、ほとんどの場合は、oracle.sqlのデータ型よりも標準Java型が優先されるようになりました。特に、java.lang.Stringは、oracle.sql.CHARよりはるかに効率的です。

一般的にはJava標準型の使用をお薦めします。例外として次のような場合があります。

- OraDataの機能の方がニーズに合っている場合は、java.sql.SqlDataではなく、oracle.sql.OraDataを使用します。

- 浮動小数点数の値を正確に保持する必要がある場合は、java.lang.Doubleではなくoracle.sql.NUMBERを使用します。Oracle NUMBERは10進表現ですが、Java DoubleおよびFloatは2進表現となります。ある形式から別の形式へ変換を行うと、実際の表現値が少し変化することがあります。さらに、2つの形式を使用して表現できる値の範囲が異なります。
パフォーマンスが重大で、値を操作せずに、単に値の読取りや書込みを行う場合には、java.math.BigDecimalではなく、oracle.sql.NUMBERを使用します。

- JDK 1.6以前のバージョンを使用している場合、または最大限のパフォーマンスを実現する必要がある場合は、java.sql.Dateまたはjava.sql.Timestampではなく、oracle.sql.DATEまたはoracle.sql.TIMESTAMPを使用します。また、多くの日付値を読み取る場合や、ごくわずかなデータしか計算または表示しない場合にも、oracle.sqlデータ型を使用できます。

注意:
JDK 1.6より前のすべてのバージョンでは、不具合によりjava.lang.Dateおよびjava.lang.Timestampオブジェクトの作成処理が遅くなるという問題があります(特に、マルチスレッド環境において)。この不具合は、JDK 1.6で修正されました。

- Oracleキャラクタ・セットによるコードで表されている外部ソースのデータがある場合にかぎり、oracle.sql.CHARを使用します。それ以外の場合はすべて、java.lang.Stringを使用します。

- STRUCT、ARRAY、BLOB、CLOB、REFおよびROWIDはすべて、対応するJDBC標準インタフェース型の実装クラスです。したがって、JDBC標準型と同一のOracle拡張型を使用する利点はありません。

- BFILE、TIMESTAMPTZおよびTIMESTAMPLTZには、JDBC標準での表現がありません。これらのOracle拡張機能は使用する必要があります。

- 他のすべての場合には、Oracle拡張機能ではなく、標準JDBC型を使用する必要があります。

注意:
oracle.sqlデータ型をJava標準データ型に変換した場合、oracle.sqlデータ型を使用する利点は失われます。

SQL NULLデータの変換

Javaは、SQL NULLデータを、Javaの値nullで表現します。Javaデータ型は、プリミティブ型(byte、int、floatなど)とオブジェクト型(クラス・インスタンスなど)の2つのカテゴリに分類されます。プリミティブ型でNULLを表すことはできません。かわりに、JDBC仕様で定義されているように、nullを0(ゼロ)値として格納します。これは、結果の解釈時にあいまいさが生じる原因ともなります。

一方、Javaオブジェクト型はNULLを表現できます。Java言語は、nullを表現可能なプリミティブ型ごとに対応したオブジェクト・コンテナ型を定義します。オブジェクト・コンテナ型は、SQLデータがSQL NULLを明確に検出するためのターゲットとして使用する必要があります。

NULLのテスト

関係演算子を使用してNULL値同士、または他の値との比較をすることはできません。たとえば、次のSELECT文は、COMM列にNULL値が1つ以上存在する場合でも行を戻しません。

PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM EMP WHERE COMM = ?");
pstmt.setNull(1, java.sql.Types.VARCHAR);

次の例では、戻り値にNULLが含まれる可能性がある場合に値が等しいかどうかを比較する方法を示します。このコードは、COMMに値100が存在しない場合、EMP表からENAMESをNULLとして戻します。

PreparedStatement pstmt = conn.prepareStatement("SELECT ENAME FROM EMP
WHERE COMM =? OR  ((COMM IS NULL) AND (? IS NULL))");
pstmt.setBigDecimal(1, new BigDecimal(100));
pstmt.setNull(2, java.sql.Types.VARCHAR);

結果セットと文拡張機能

JDBC Statementオブジェクトは、java.sql.ResultSetとして型指定されたOracleResultSetオブジェクトを戻します。標準JDBCメソッドのみをオブジェクトに適用する場合は、オブジェクトのResultSet型を維持してください。ただし、オブジェクト上でOracle拡張機能を使用する場合は、Oracle拡張機能をOracleResultSetにキャストする必要があります。Oracleの結果セット拡張機能は、すべてoracle.jdbc.OracleResultSetインタフェースに含まれ、Statement拡張機能は、すべてoracle.jdbc.OracleStatementインタフェースに含まれています。

たとえば、標準Statementオブジェクトstmtがあり、標準JDBC ResultSetメソッドのみを使用する場合、次のように記述します。

ResultSet rs = stmt.executeQuery("SELECT * FROM emp");

JDBCに対するOracle拡張機能を使用する場合は、結果を選択して標準ResultSet変数に入れ、次にその変数をOracleResultSetにキャストします。

結果セット・クラスおよび文クラスへの主な拡張機能には、getOracleObjectおよびsetOracleObjectメソッドがあります。これらのメソッドは、oracle.sql.*形式でデータへのアクセスおよび操作を実行するために使用します。

Oracleのgetおよびsetメソッドと標準JDBCの比較

この項では、getメソッドとsetメソッド、特にJDBC標準のgetObjectメソッドとsetObjectメソッドおよびOracle固有のgetOracleObjectメソッドとsetOracleObjectメソッドについて説明します。また、oracle.sql.*形式のデータへのアクセス方法をJava形式と比較しながら説明します。

Oracle SQL型にはすべて、対応する特定のgetXXXメソッドがありますが、便宜上または簡単にするために、あるいは受け取るデータの型が不明な場合には、一般的なgetメソッドを使用できます。

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

- 標準getObjectメソッド

- Oracle getOracleObjectメソッド

- getObjectおよびgetOracleObject戻り型のまとめ

- その他のgetXXXメソッド

- getObjectおよびgetXXXから戻されるオブジェクトのデータ型

- setObjectメソッドとsetOracleObjectメソッド

- その他のsetXXXメソッド

注意:
表名を使用して列名を修飾し、その列名をパラメータとしてgetXXXメソッドに渡すことはできません。たとえば、次のようになります。

ResultSet rset = stmt.executeQuery("SELECT emp.deptno, dept.deptno FROM emp, dept");
rset.getInt("emp.deptno");

このコード例の場合、getIntメソッドで例外が発生します。getXXXメソッドで列を一意に識別するには、列索引を使用するか、または問合せで列別名を指定してその別名をgetXXXメソッドで使用します。

標準getObjectメソッド

結果セットまたはコール可能文の標準getObjectメソッドの戻り型は、java.lang.Objectです。戻されるオブジェクトのクラスは、次に示すようにSQL型に基づきます。

- Oracle固有ではないSQLデータ型の場合、JDBC仕様のマッピングに従い、getObjectは列のSQL型に対応するデフォルトのJava型を戻します。

- Oracle固有のデータ型の場合、getObjectは適切なoracle.sql.*クラス(oracle.sql.ROWIDなど)のオブジェクトを戻します。

- Oracleデータベース・オブジェクトの場合、getObjectは、使用する型マップで指定されたクラスのJavaオブジェクトを戻します。型マップは、データベース型名からJavaクラスへのマッピングを指定します。getObject(parameter_index)メソッドでは、接続のデフォルト型マップを使用します。getObject(parameter_index, map)を使用すると、型マップを渡すことができます。型マップが特定のOracleオブジェクトのマッピングを提供しない場合、getObjectはoracle.sql.STRUCTオブジェクトを戻します。

Oracle getOracleObjectメソッド

結果セットまたはコール可能文からデータをoracle.sql.*オブジェクトとして取り出す場合は、特殊なプロセスに従う必要があります。結果セットの場合は、結果セット自体をoracle.jdbc.OracleResultSetにキャストしてから、getObjectのかわりにgetOracleObjectをコールする必要があります。CallableStatementおよびoracle.jdbc.OracleCallableStatementにも同じことが当てはまります。

getOracleObjectの戻り型はoracle.sql.Datumです。実際に戻されるオブジェクトは、該当するoracle.sql.*クラスのインスタンスです。メソッド・シグネチャは次のとおりです。

public oracle.sql.Datum getOracleObject(int parameter_index)

Datum変数に取り出したデータを入れると、標準Java instanceof演算子を使用して、実際にどのoracle.sql.*型であるかを確認できます。

例: 結果セットでのgetOracleObjectの使用方法

次の例では、CHARデータの列を含む表およびBFILEロケータを含む列を作成します。SELECT文では、表の内容を結果セットとして取り出します。その後、getOracleObjectで取り出したCHARデータをchar_datum変数に、BFILEロケータをbfile_datum変数に入れます。getOracleObjectはDatumオブジェクトを戻すため、戻り値をそれぞれCHARおよびBFILEにキャストする必要があります。

stmt.execute ("CREATE TABLE bfile_table (x VARCHAR2 (30), b BFILE)");
stmt.execute
("INSERT INTO bfile_table VALUES ('one', BFILENAME ('TEST_DIR', 'file1'))");

ResultSet rset = stmt.executeQuery ("SELECT * FROM bfile_table");
while (rset.next ())
{
CHAR char_datum = (CHAR) ((OracleResultSet)rset).getOracleObject (1);
BFILE bfile_datum = (BFILE) ((OracleResultSet)rset).getOracleObject (2);
...
}

例: コール可能文でのgetOracleObjectの使用方法

次の例では、文字列を日付と関連付けるプロシージャmyGetDateへのコールを作成します。このプログラムは、SCOTTを準備済コールに渡し、DATE型を出力パラメータとして登録します。コールの実行後、getOracleObjectはSCOTTに関連付けられている日付を取り出します。getOracleObjectはDatumオブジェクトを戻すため、結果はDATEにキャストされる点に留意してください。

OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall
("begin myGetDate (?, ?); end;");

cstmt.setString (1, "SCOTT");
cstmt.registerOutParameter (2, Types.DATE);
cstmt.execute ();

DATE date = (DATE) ((OracleCallableStatement)cstmt).getOracleObject (2);
...

getObjectおよびgetOracleObject戻り型のまとめ

表11-2は、各Oracle SQL型のgetObjectメソッドとgetOracleObjectメソッドの、基礎となる戻り型を示しています。

ただし、これらのメソッドを使用する際は、次のことを念頭に置いてください。

- getObjectは、データを常にjava.lang.Objectインスタンスで戻します。

- getOracleObjectは、データを常にoracle.sql.Datumインスタンスで戻します。

特殊機能を使用するには、戻されたオブジェクトをキャストする必要があります。

表11-2 getObjectとgetOracleObjectの戻り型

Oracle SQL型

getObjectの基礎となる戻り型

getOracleObjectの基礎となる戻り型

CHAR

String

oracle.sql.CHAR

VARCHAR2

String

oracle.sql.CHAR

NCHAR

String

oracle.sql.CHAR

LONG

String

oracle.sql.CHAR

NUMBER

java.math.BigDecimal

oracle.sql.NUMBER

RAW

byte[]

oracle.sql.RAW

LONGRAW

byte[]

oracle.sql.RAW

DATE

java.sql.Date

oracle.sql.DATE

TIMESTAMP

java.sql.Timestamp脚注1

oracle.sql.TIMESTAMP

TIMESTAMPWITHTIMEZONE

oracle.sql.TIMESTAMPLTZ

oracle.sql.TIMESTAMPLTZ

TIMESTAMPWITHLOCALTIMEZONE

oracle.sql.TIMESTAMPLTZ

oracle.sql.TIMESTAMPLTZ

BINARY_FLOAT

java.lang.Float

oracle.sql.BINARY_FLOAT

BINARY_DOUBLE

java.lang.Double

oracle.sql.BINARY_DOUBLE

INTERVALDAYTOSECOND

oracle.sql.INTERVALDS

oracle.sql.INTERVALDS

INTERVALYEARTOMONTH

oracle.sql.INTERVALYM

oracle.sql.INTERVALYM

ROWID

oracle.sql.ROWID

oracle.sql.ROWID

REF CURSOR

java.sql.ResultSet

(未サポート)

BLOB

oracle.sql.BLOB

oracle.sql.BLOB

CLOB

oracle.sql.CLOB

oracle.sql.CLOB

NCLOB

java.sql.NClob

oracle.sql.NCLOB

BFILE

oracle.sql.BFILE

oracle.sql.BFILE

Oracleオブジェクト

型マップで指定されたクラス

またはoracle.sql.STRUCT(型マップにエントリがない場合)

oracle.sql.STRUCT

Oracleオブジェクト参照

oracle.sql.REF

oracle.sql.REF

コレクション(VARRAYまたはNESTED TABLE)

oracle.sql.ARRAY

oracle.sql.ARRAY

脚注1 ResultSet.getObjectは、oracle.jdbc.J2EE13Compliant接続プロパティがTRUEに設定されている場合のみjava.sql.Timestampを戻します。そうでない場合、このメソッドはoracle.sql.TIMESTAMPを戻します。

注意:
ResultSet.getObjectメソッドは、接続プロパティoracle.jdbc.J2EE13CompliantがTRUEに設定されている場合のみ、TIMESTAMP SQL型のjava.sql.Timestampを戻します。このプロパティは、接続の取得時に設定する必要があります。この接続プロパティが設定されていない場合、または接続の取得後に設定した場合、ResultSet.getObjectメソッドはTIMESTAMP SQL型のoracle.sql.TIMESTAMPを戻します。
oracle.jdbc.J2EE13Compliant接続プロパティは、コードを変更せずに、次の方法で設定できます。

- ojdbc5dms.jarファイルまたはojdbc6dms.jarファイルをCLASSPATHに含めます。これらのファイルでは、デフォルトでoracle.jdbc.J2EE13CompliantがTRUEに設定されます。これらはOracle Application Serverリリースに固有のもので、一般のJDBCリリースには含まれていません。これらのファイルは$ORACLE_HOME/jdbc/libにあります。

- javaコマンドをフラグ-Doracle.jdbc.J2EE13Compliant=trueを指定してコールし、システム・プロパティを設定します。たとえば、次のようになります。

java -Doracle.jdbc.J2EE13Compliant=true ...

J2EE13CompliantがTRUEに設定されると、動作はJDBC仕様の表B-3のようになります。

関連項目:
すべてのSQL型とJava型との型互換性については、表A-1「有効なSQLデータ型-Javaクラス・マッピング」を参照してください。

その他のgetXXXメソッド

標準JDBCでは、各標準Java型に対応したgetXXX(getByte、getInt、getFloatなど)が提供されます。これらの各メソッドは、そのメソッド名が意味する内容を正確に戻します。

さらに、OracleResultSetクラスとOracleCallableStatementクラスは、すべてのoracle.sql.*型に対応したgetXXXメソッドを補完します。各getXXXメソッドは、oracle.sql.XXXオブジェクトを戻します。たとえば、getROWIDメソッドは、oracle.sql.ROWIDオブジェクトを戻します。

特定のgetXXXメソッドを使用してもパフォーマンス上の利点はありません。ただし、戻り型は戻されるオブジェクトに固有であるため、面倒なキャストの必要がなくなります。

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

- getXXXメソッドの戻り型

- getXXXメソッドに関する特別な注意

getXXXメソッドの戻り型

各々のgetXXXメソッドの戻り型や、Java Development Kit (JDK) 1.6に含まれるOracle拡張機能については、Javadocを参照してください。戻されたオブジェクトをOracleResultSetまたはOracleCallableStatementにキャストして、Oracle拡張機能であるメソッドを使用する必要があります。

getXXXメソッドに関する特別な注意

この項では、いくつかのgetXXXメソッドについて追加の詳細情報を示します。

getBigDecimal

JDBC 2.0では、getBigDecimalメソッドのメソッド・シグネチャが単純になっています。以前の入力シグネチャは次のいずれかでした。

(int columnIndex, int scale) or (String columnName, int scale)

単純になった入力シグネチャは次のとおりです。

(int columnIndex) or (String columnName)

小数点の右にある数字の数を指定するために使用するscaleパラメータは不要になりました。Oracle JDBCドライバは、完全な精度で数値を取り出します。

getBoolean

BOOLEANデータベース型が存在しないため、getBooleanを使用すると必ずデータ型変換が実行されます。getBooleanメソッドは数値用の列に対してのみサポートされます。このような列に対してgetBooleanが適用されると、0(ゼロ)値はfalseとして、それ以外の値はtrueとして解釈されます。別の種類の列に適用された場合は、getBooleanは例外java.lang.NumberFormatExceptionを戻します。

getObjectおよびgetXXXから戻されるオブジェクトのデータ型

getObjectの戻り型はjava.lang.Objectです。戻り型は、java.lang.Objectのサブクラスのインスタンスです。同様に、getOracleObjectの戻り型はoracle.sql.Datumで、戻り値のクラスはoracle.sql.Datumのサブクラスです。通常、適切なクラスの特定のメソッドおよび機能を使用するには、戻されたオブジェクトをそのクラスにキャストします。

また、汎用のgetObjectメソッドやgetOracleObjectメソッドのかわりに、特定のgetXXXメソッドも使用できます。getXXXの戻り型は、戻されるオブジェクトの型に対応しているため、getXXXメソッドを使用することにより、キャストを回避できます。たとえば、getCLOBの戻り型は、java.lang.Objectではなくoracle.sql.CLOBです。

戻り値のキャストの例

この例では、NUMBERタイプのデータを結果セットの最初の列としてフェッチしていると想定しています。精度を下げずにNUMBERデータを操作する必要があるので、OracleResultSetに結果セットをキャストし、getOracleObjectを使用して、NUMBERデータをoracle.sql.*形式で戻します。結果セットをキャストしない場合は、getObjectを使用する必要があります。数値データがJava Floatに戻されるため、SQLデータの精度が多少下がります。

getOracleObjectメソッドは、出力をキャストしないかぎり、oracle.sql.NUMBERオブジェクトをoracle.sql.Datum戻り変数に戻します。NUMBER戻り変数を使用し、そのクラスの特殊機能のいずれかを使用する場合は、getOracleObjectの出力をoracle.sql.NUMBERにキャストしてください。

NUMBER x = (NUMBER)ors.getOracleObject(1);

setObjectメソッドとsetOracleObjectメソッド

結果セットとコール可能文に標準getObjectとOracle固有のgetOracleObjectがあるように、OraclePreparedStatementとOracleCallableStatementにも標準setObjectメソッドとOracle固有のsetOracleObjectメソッドがあります。setOracleObjectメソッドは、oracle.sql.*を入力パラメータとして取ります。

標準Java型をプリコンパイルされたSQL文またはコール可能文にバインドするには、java.lang.Objectを入力にとるsetObjectメソッドを使用します。setObjectメソッドは、いくつかのoracle.sql.*型をサポートします。ただしこのメソッドは、JDBC標準型Blob、Clob、Struct、RefおよびArrayに対応するoracle.sql.*クラスのインスタンスを入力できるように実装されています。

oracle.sql.*型をプリコンパイルされたSQL文またはコール可能文にバインドするには、oracle.sql.Datumのサブクラスを入力にとるsetOracleObjectメソッドを使用します。setOracleObjectを使用するには、プリコンパイルされたSQL文またはコール可能文をOraclePreparedStatementまたはOracleCallableStatementにキャストする必要があります。

setObjectとsetOracleObjectの使用例

プリコンパイルされたSQL文には、charVal変数により表現されたoracle.sql.CHARデータがsetOracleObjectメソッドによってバインドされます。oracle.sql.*データをバインドするには、プリコンパイルされたSQL文をOraclePreparedStatementにキャストする必要があります。同様に、setObjectメソッドは、変数strValで表現されたJava Stringデータをバインドします。

PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
((OraclePreparedStatement)ps).setOracleObject(1,charVal);
ps.setObject(2,strVal);

その他のsetXXXメソッド

getXXXメソッドと同様に、固有なsetXXXメソッドもいくつかあります。標準のsetXXXメソッドはJava型をバインドするために、Oracle固有のsetXXXメソッドはOracle固有の型をバインドするために提供されています。

同様に、setNullメソッドには次の2つの形式があります。

- void setNull(int parameterIndex, int sqlType)
これは、標準のjava.sql.PreparedStatementインタフェースで指定されるシグネチャです。このシグネチャは、java.sql.Typesクラスまたはoracle.jdbc.OracleTypesクラスによって定義されるパラメータ索引とSQL型コードを取ります。REF、ARRAYまたはSTRUCT以外のオブジェクトをNULLに設定する場合は、このシグネチャを使用します。

- void setNull(int parameterIndex, int sqlType, String sql_type_name)
JDBC 2.0の場合、このシグネチャは標準のjava.sql.PreparedStatementインタフェースにも指定されます。このメソッドは、パラメータ索引およびSQL型コードに加え、SQL型名を取ります。このメソッドは、SQL型コードがjava.sql.Types.REF、ARRAYまたはSTRUCTの場合に使用します。型コードがREF、ARRAYまたはSTRUCT以外の場合、指定されたSQL型名は無視されます。

同様に、registerOutParameterメソッドには、REF、ARRAYまたはSTRUCTデータとともに使用するためのシグネチャがあります。

void registerOutParameter
(int parameterIndex, int sqlType, String sql_type_name)

標準Java型のバインドのためのメソッドではなく、適切なsetXXXメソッドを使用してOracle固有型をバインドすると、多少パフォーマンスが向上することがあります。

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

- 入力データのバインド

- WHERE句にCHARデータをバインドするためのメソッドsetFixedCHAR

入力データのバインド

入力用のデータのバインド方法は3つあります。

- データ自体をバインド・バッファに格納するダイレクト・バインド

- データをストリーム処理するストリーム・バインド

- 一時LOBを作成し、LOB APIを使用してデータをそのLOBに格納し、LOBロケータのバイトをバインド・バッファに格納するLOBバインド

3種類のバインドはパフォーマンスが異なり、バッチ処理に影響を与えます。ダイレクト・バインドは最も高速で、バッチ処理が正常に行われます。ストリーム・バインドはより低速で、複数のラウンドトリップが必要な場合があり、バッチ処理はオフになります。LOBバインドは非常に低速で、多数のラウンドトリップが必要です。バッチ処理は機能しますが、お薦めできません。これらのバインドでは、SQL文の型に応じてサイズの制限も異なります。

SQLパラメータについては、RAWやVARCHAR2など標準のパラメータ型の長さはターゲット列のサイズによって固定されます。PL/SQLパラメータについては、サイズは32766という固定バイト数に制限されます。

Oracle Database 10gリリース2(10.2)では、PreparedStatementのsetString、setCharacterStream、setAsciiStream、setBytesおよびsetBinaryStreamメソッドが一部変更されています。APIの当初の動作は次のとおりでした。

- setString: キャラクタのダイレクト・バインド

- setCharacterStream: キャラクタのストリーム・バインド

- setAsciiStream: バイトのストリーム・バインド

- setBytes: バイトのダイレクト・バインド

- setBinaryStream: バイトのストリーム・バインド

Oracle Database 10gリリース2(10.2)以降、データ・サイズおよびSQL文の型に基づくバインド・モードの自動切替えがサポートされています。

setBytesおよびsetBinaryStream

SQLでは、サイズが2000以下の場合はダイレクト・バインド、2000を超える場合はストリーム・バインドが使用されます。

PL/SQLでは、サイズが32766以下の場合はダイレクト・バインド、32766を超える場合はLOBバインドが使用されます。

setString、setCharacterStreamおよびsetAsciiStream

SQLでは、Javaキャラクタが32766以下の場合はダイレクト・バインド、32766を超える場合はストリーム・バインドが使用されます。これはキャラクタ・セットに依存しません。

PL/SQLでは、使用形式パラメータの設定に応じて、データベース・キャラクタ・セットまたは各国語キャラクタ・セット内のキャラクタ・データのバイト・サイズに注意する必要があります。バイト長が32766未満のデータにはダイレクト・バインド、32766以上のデータにはLOBバインドが使用されます。

固定長キャラクタ・セットについては、Javaキャラクタ・データの長さにバイト単位の固定文字サイズをかけた値を上限値と比較します。可変長キャラクタ・セットについては、Javaキャラクタの長さに応じて、次の3つの場合があります。

- 文字長が32766を最大文字サイズで割った値よりも小さい場合は、ダイレクト・バインドが使用されます。

- 文字長が32766を最小文字サイズで割った値よりも大きい場合は、LOBバインドが使用されます。

- 文字長がその間であり、変換済バイトの実際の長さが32766未満の場合は、ダイレクト・バインドが使用され、それ以外の場合はLOBバインドが使用されます。

注意:
PL/SQLプロシージャがSQL文に埋め込まれている場合、バインド処理は異なります。詳細は、「LOBのデータ・インタフェース」を参照してください。

サーバー側内部ドライバには、他にも次の制限事項があります。

- データ・サイズの文字数が4000バイトを超える場合、setString、setCharacterStreamおよびsetASCIIStreamの各APIはSQL CLOB列ではサポートされていません。

- データ・サイズが2000バイトを超える場合、setBytesおよびsetBinaryStreamの各APIはSQL BLOB列ではサポートされていません。

重要:
サーバー側内部ドライバでこれらのAPIを使用する場合は、クライアント・コードのデータ・サイズを入念にチェックしてください。

関連項目:
詳細な説明および考えられる対応策は、JDBCのリリース・ノートを参照してください。

WHERE句にCHARデータをバインドするためのメソッドsetFixedCHAR

データベース内のCHARデータは、列幅まで埋め込まれます。このため、SELECT文のWHERE句に文字データをバインドするためのsetCHARメソッドの使用に関して、制限が生じます。WHERE句の文字データも、SELECT文で合致させるために、列幅まで埋め込む必要があります。これは特に列幅がわからない場合に問題になります。

これを修正するために、OracleはOraclePreparedStatementクラスにsetFixedCHARメソッドを追加しました。このメソッドは埋込みなしの比較を実行します。

注意:

- setFixedCHARメソッドを使用するには、必ずプリコンパイルされたSQL文オブジェクトをOraclePreparedStatementにキャストしてください。

- INSERT文で、setFixedCHARを使用する必要はありません。データベースは挿入時に、常にそのデータを列幅まで自動的に埋め込みます。

例

次の例では、setCHARメソッドとsetFixedCHARメソッドの違いを示します。

/* Schema is :
create table my_table (col1 char(10));
insert into my_table values ('JDBC');
*/
PreparedStatement pstmt = conn.prepareStatement
("select count(*) from my_table where col1 = ?");

pstmt.setString (1, "JDBC");  // Set the Bind Value
runQuery (pstmt);             // This will print " No of rows are 0"

CHAR ch = new CHAR("JDBC      ", null);
((OraclePreparedStatement)pstmt).setCHAR(1, ch); // Pad it to 10 bytes
runQuery (pstmt);             // This will print "No of rows are 1"

((OraclePreparedStatement)pstmt).setFixedCHAR(1, "JDBC");
runQuery (pstmt);            // This will print "No of rows are 1"

void runQuery (PreparedStatement ps)
{
// Run the Query
ResultSet rs = pstmt.executeQuery ();

while (rs.next())
System.out.println("No of rows are " + rs.getInt(1));

rs.close();
rs = null;
}

結果セット・メタデータ拡張機能の使用方法

oracle.jdbc.OracleResultSetMetaDataインタフェースはJDBC 2.0に準拠していますが、Oracle Databaseによってサポートされていないため、getSchemaNameメソッドとgetTableNameメソッドは実装されません。

次のコードは、OracleResultSetMetadataインタフェースのメソッドをいくつか使用して、EMP表から列数を取り出し、各列の数値型とSQL型名を取り出します。

DatabaseMetaData dbmd = conn.getMetaData();
ResultSet rset = dbmd.getTables("", "SCOTT", "EMP", null);

while (rset.next())
{
OracleResultSetMetaData orsmd = ((OracleResultSet)rset).getMetaData();
int numColumns = orsmd.getColumnCount();
System.out.println("Num of columns = " + numColumns);

for (int i=0; i<numColumns; i++)
{
System.out.print ("Column Name=" + orsmd.getColumnName (i+1));
System.out.print (" Type=" + orsmd.getColumnType (i + 1) );
System.out.println (" Type Name=" + orsmd.getColumnTypeName (i + 1));
}
}

このプログラムは次の出力を戻します。

Num of columns = 5
Column Name=TABLE_CAT Type=12 Type Name=VARCHAR2
Column Name=TABLE_SCHEM Type=12 Type Name=VARCHAR2
Column Name=TABLE_NAME Type=12 Type Name=VARCHAR2
Column Name=TABLE_TYPE Type=12 Type Name=VARCHAR2
Column Name=TABLE_REMARKS Type=12 Type Name=VARCHAR2

SQL CALL文とCALL INTO文の使用

CALL文を使用してSQL内からルーチンを実行できます。

注意:
ルーチンとは、スタンドアロンのプロシージャまたは関数や、型またはパッケージ内で定義されているプロシージャまたは関数です。スタンドアロンのルーチン上、またはルーチンが定義されている型やパッケージ上で、EXECUTE権限を持っている必要があります。CALL文の使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ルーチンは、次の2つの方法で実行できます。

- コールをルーチン自身に名前で送信するか、routine_clauseを使用します。

- 式の型の内部でobject_access_expressionを使用します。

ルーチンが引数を取る場合は、引数を指定できます。引数には、位置表記、名前表記または混合表記を使用できます。

CALL INTO文

INTO句は関数のコールにのみ適用されます。この句には次の型の変数を使用できます。

- ホスト変数

- 標識変数

PL/SQLブロック

PL/SQLの基本単位は、ブロックです。すべてのPL/SQLプログラムはブロックで構成されており、ブロックは互いの内部にネストすることができます。PL/SQLブロックには、宣言部、実行部、例外処理部の3つの部分があります。アプリケーションでPL/SQLブロックを使用すると、次の利点があります。

- パフォーマンスの向上

- 生産性の向上

- 完全な移植性

- Oracleとの密接な統合

- 厳重なセキュリティ

12 JDBC内のJavaストリーム

この章では、Oracle Java Database Connectivity(JDBC)ドライバで様々なデータ型のJavaストリームを処理する方法を説明します。データ・ストリームを使用することにより、最大2GBのLONG型列データを読み取れます。ストリームに関連付けられたメソッドを使用すると、データを増分的に読み取れます。

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

- Javaストリームの概要

- LONGまたはLONG RAW列のストリーム

- CHAR、VARCHARまたはRAW列のストリーム

- LOBおよび外部ファイルのストリーム

- データ・ストリームと複数列

- ストリームと行のプリフェッチ

- ストリームのクローズ

- ストリームに関する注意

Javaストリームの概要

Oracle JDBCドライバは、サーバーとクライアント間の双方向のデータ・ストリーム操作をサポートします。ドライバは、すべてのストリーム変換、つまりバイナリ、ASCIIおよびUnicodeをサポートします。次に、ストリームの各タイプを簡単に説明します。

- バイナリ
データのRAWバイトのために使用されます。getBinaryStreamメソッドに対応します。

- ASCII
ISO-Latin-1エンコーディングでASCIIバイトのために使用されます。getAsciiStreamメソッドに対応します。

- Unicode
UTF-16エンコーディングでUnicodeバイトのために使用されます。getUnicodeStreamメソッドに対応します。

getBinaryStream、getAsciiStreamおよびgetUnicodeStreamの各メソッドは、InputStreamオブジェクト内のデータ・バイトを戻します。

関連項目:
第14章「LOBとBFILEの操作」

LONGまたはLONG RAW列のストリーム

問合せがLONGまたはLONG RAW列を1つ以上選択すると、JDBCドライバは、ストリーム・モードでこれらの列をクライアントに転送します。ストリーム・モードでは、JDBCドライバは、必要になるまでLONGまたはLONG RAW列のためにネットワークから列データを読み取りません。コードでgetXXXメソッドを呼び出して列データを読み取るまで、列データはネットワーク通信チャネルに残っています。コールの後でも、列データは、getXXXコールから戻り値にデータを移入する場合にのみ読み取られます。列データが通信チャネルに残っているため、ストリーム・モードは他のすべての接続の使用を妨げます。列データの読取り以外で接続を使用すると、チャネルから列データが廃棄されます。ストリーム・モードはメモリーを効率よく使用し、ネットワークのラウンドトリップを最小限に抑えますが、他の多くのデータベース操作の妨げになります。

注意:
LONGおよびLONG RAW列は使用しないことをお薦めします。かわりにLOBを使用してください。

LONG列のデータにアクセスするには、この列をJava InputStreamオブジェクトとして取得し、InputStreamオブジェクトのreadメソッドを使用します。また、データをStringまたはbyte配列として取得することもできます。この場合、ドライバによってストリーム処理が実行されます。

3種類のストリームのうち、任意のものを使用して、LONGまたはLONG RAWデータを取得できます。ドライバは、データベースおよびドライバのキャラクタ・セットに応じて、変換を行います。

注意:
LONG列を使用した表を作成しないでください。かわりに、ラージ・オブジェクト(LOB)列CLOB、NCLOBおよびBLOBを使用してください。LONG列は、下位互換性のみのためにサポートされています。また、既存のLONG列をLOB列に変換することをお薦めします。LOB列に対する制約は、LONG列に比べてはるかに少なくなります。

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

- LONGまたはLONG RAW列のストリーム

- CHAR、VARCHARまたはRAW列のストリーム

- LOBおよび外部ファイルのストリーム

- データ・ストリームと複数列

- ストリームのクローズ

- ストリームに関する注意

LONG RAWデータの変換

getBinaryStreamへのコールにより、RAWデータが戻されます。getAsciiStreamへのコールにより、RAWデータが16進データに変換され、ASCIIコードが戻されます。getUnicodeStreamへのコールにより、RAWデータが16進データに変換され、Unicode文字が戻されます。

LONGデータの変換

getAsciiStreamを使用してLONGデータを取得した場合、ドライバは、データベースに格納されている基礎となるデータにUS7ASCIIまたはWE8ISO8859P1キャラクタ・セットが使用されているものとみなします。実際にそうである場合、ドライバはASCII文字に対応するバイトを戻します。データベースでUS7ASCIIとWE8ISO8859P1のいずれのキャラクタ・セットも使用されていない場合、getAsciiStreamへのコールを実行すると、意味のないコードが戻されます。

getUnicodeStreamを使用してLONGデータを取得すると、Unicode文字のストリームがUTF-16エンコーディングで戻されます。これは、Oracleがサポートする、データベースの基礎となるキャラクタ・セットすべてに当てはまります。

getBinaryStreamを使用してLONGデータを取得する場合、次の2つのケースが考えられます。

- ドライバがJDBC OCIで、クライアントのキャラクタ・セットがUS7ASCIIまたはWE8ISO8859P1でない場合、getBinaryStreamをコールするとUTF-8が戻されます。クライアントのキャラクタ・セットがUS7ASCIIまたはWE8ISO8859P1に設定されている場合、US7ASCIIバイト・ストリームが戻されます。

- ドライバがJDBC Thinで、データベースのキャラクタ・セットがUS7ASCIIまたはWE8ISO8859P1でない場合、getBinaryStreamをコールするとUTF-8が戻されます。サーバー側キャラクタ・セットがUS7ASCIIまたはWE8ISO8859P1に設定されている場合、US7ASCIIバイト・ストリームが戻されます。

ヒント:
第19章「グローバリゼーション・サポート」および「データ・ストリームと複数列」

注意:
LONGまたはLONG RAW列をストリームとして受信するには、データベースから取り出す列の順序に注意する必要があります。

表12-1に、LONGおよびLONG RAWデータ変換の概要をストリーム・タイプ別に示します。

表12-1 LONGおよびLONG RAWデータの変換

データ型

BinaryStream

AsciiStream

UnicodeStream

LONG

Unicode UTF-8の文字を表すバイト。データベース・キャラクタ・セットがUS7ASCIIまたはWE8ISO8859P1の場合、バイトはUS7ASCIIまたはWE8ISO8859P1のキャラクタを表します。

ISO-Latin-1(WE8ISO8859P1)エンコーディングの文字を表すバイト。

Unicode UTF-16エンコーディングの文字を表すバイト。

LONG RAW

データの変換なし。

16進バイトのASCII表現。

16進バイトのUnicode表現。

LONG RAWデータのストリーム例

getXXXStreamメソッドには、データの増分的取得を可能にする機能があります。一方、getBytesは、すべてのデータを一度のコールでフェッチします。この項には、バイナリ・データ・ストリームの取得方法を示す2つの例が含まれています。LONG RAWデータを取得するのに、最初のバージョンではgetBinaryStreamメソッドを使用し、2番目のバージョンではgetBytesメソッドを使用します。

getBinaryStreamを使用したLONG RAWデータ列の取得

この例では、ローカル・ファイルシステム上のファイルにLONG RAW列の内容を書き込みます。この場合、ドライバはデータを増分的にフェッチします。

次のコードは、名前LESLIEに関連付けられたLONG RAWデータ列を格納する表を作成します。

-- SQL code:
create table streamexample (NAME varchar2 (256), GIFDATA long raw);
insert into streamexample values ('LESLIE', '00010203040506070809');

次のJavaコードの一部は、LONG RAW列のデータを、leslie.gifというファイルに書き込みます。

ResultSet rset = stmt.executeQuery
("select GIFDATA from streamexample where NAME='LESLIE'");

// get first row
if (rset.next())
{
// Get the GIF data as a stream from Oracle to the client
InputStream gif_data = rset.getBinaryStream (1);
try
{
FileOutputStream file = null;
file = new FileOutputStream ("leslie.gif");
int chunk;
while ((chunk = gif_data.read()) != -1)
file.write(chunk);
}
catch (Exception e)
{
String err = e.toString();
System.out.println(err);
}
finally
{
if file != null()
file.close();
}
}

この例では、getBinaryStreamへのコールにより戻されるInputStreamオブジェクトは、データベース接続から直接データを読み取ります。

getBytesを使用したLONG RAWデータ列の取得

この例では、getBinaryStreamのかわりにgetBytesを使用して、GIFDATA列の内容を取得します。この場合、ドライバは一度のコールですべてのデータをフェッチして、バイト配列に格納します。コードは次のようになります。

ResultSet rset2 = stmt.executeQuery
("select GIFDATA from streamexample where NAME='LESLIE'");

// get first row
if (rset2.next())
{
// Get the GIF data as a stream from Oracle to the client
byte[] bytes = rset2.getBytes(1);
try
{
FileOutputStream file = null;
file = new FileOutputStream ("leslie2.gif");
file.write(bytes);
}
catch (Exception e)
{
String err = e.toString();
System.out.println(err);
}
finally
{
if file != null()
file.close();
}
}

LONG RAW列では最大2GBのデータを格納できるため、getBytesの使用例では、getBinaryStreamの使用例に比べて多量のメモリーを使用できます。LONGまたはLONG RAW列のデータの最大サイズが不明な場合は、ストリームを使用してください。

LONGまたはLONG RAWのストリーム回避

JDBCドライバは、任意のLONGおよびLONG RAW列を自動的にストリーム処理します。ただし、データ・ストリームを避ける状況が生じる場合もあります。たとえば、LONG列のサイズが非常に小さい場合、データが増分的ではなく、一度のコールで戻される方が望ましい場合があります。

ストリームを回避するには、defineColumnTypeメソッドを使用してLONG列の型を再定義します。たとえば、LONGまたはLONG RAW列をVARCHAR型またはVARBINARY型として再定義すると、ドライバがデータを自動的にストリーム処理することはなくなります。

defineColumnTypeを使用して列の型を再定義する場合、問合せの中で列の型を宣言する必要があります。列の型を宣言しないと、executeQueryが失敗します。また、Statementオブジェクトをoracle.jdbc.OracleStatementオブジェクトにキャストする必要があります。

さらに、defineColumnTypeを使用すると、問合せの実行時にOCIとKPRBの各ドライバがデータベースへ往復せずにすみます。defineColumnTypeを使用しない場合、これらのJDBCドライバは列タイプのデータ型を要求する必要があります。JDBC Thinドライバでは、ラウンドトリップの回数が常に最小であるため、defineColumnTypeを使用する利点はありません。

前の項の例を使用して、StatementオブジェクトstmtはOracleStatementへキャストされ、LONG RAWデータを含む列はVARBINARAY型として再定義されます。このデータはストリーム化されません。かわりに、バイト配列で戻されます。コードは次のようになります。

//cast the statement stmt to an OracleStatement
oracle.jdbc.OracleStatement ostmt =
(oracle.jdbc.OracleStatement)stmt;

//redefine the LONG column at index position 1 to VARBINARY
ostmt.defineColumnType(1, Types.VARBINARY);

// Do a query to get the images named 'LESLIE'
ResultSet rset = ostmt.executeQuery
("select GIFDATA from streamexample where NAME='LESLIE'");

// The data is not streamed here
rset.next();
byte [] bytes = rset.getBytes(1);

CHAR、VARCHARまたはRAW列のストリーム

defineColumnType Oracle拡張機能を使用してCHAR、VARCHARまたはRAW列をLONGVARCHARまたはLONGVARBINARYとして再定義する場合は、列をストリームとして取得できます。このプログラムは、列が実際にLONGまたはLONG RAW型であるかのように動作します。通常これらの列は短いため、これが問題になることはほとんどありません。

CHAR、VARCHARまたはRAW列を、列タイプを再定義することなくデータ・ストリームとして取得しようとすると、JDBCドライバはJava InputStreamを戻しますが、実際のストリームは発生しません。これらのデータ型の場合、JDBCドライバは、executeQueryメソッドまたはnextメソッドへのコール中に、データをメモリー内のバッファに完全にフェッチします。getXXXStreamエントリ・ポイントは、このバッファからデータを読み取るストリームを戻します。

LOBおよび外部ファイルのストリーム

ラージ・オブジェクト(LOB)という用語は、データベース表に直接格納するには大きすぎるデータ項目を指します。一方、ロケータはデータベース表に格納されて、実際のデータの場所を指します。外部ファイルも同様に管理されます。JDBCドライバは、ストリームの使用によって次の型をサポートできます。

- バイナリ・ラージ・オブジェクト(BLOB)
非構造化バイナリ・データ用

- キャラクタ・ラージ・オブジェクト(CLOB)
文字データ用

- 各国語キャラクタ・ラージ・オブジェクト(NCLOB)
各国語キャラクタ・データ用

- バイナリ・ファイル(BFILE)
外部ファイル用

LOBとBFILEは、この章で説明した他のストリーム・データとは動作が異なります。表に実際のデータが格納されるかわりに、ロケータが格納されます。ストリームとしてのデータの読取りおよび書込みなど、実際のデータを操作するには、このロケータを使用します。ストリーム処理の場合も、データの必要なビットのみがネットワーク間を移動します。これに対して、LONGまたはLONG RAWをストリーム処理するときは、常にすべてのデータがネットワーク間を移動します。

BLOB、CLOBおよびNCLOBのストリーム

問合せにより、1つ以上のBLOB、CLOBまたはNCLOB列をフェッチすると、JDBCドライバはデータをクライアントに転送します。このデータはストリームとしてアクセスできます。JDBCより取得したBLOB、CLOBまたはNCLOBデータを操作する場合、Oracleの拡張機能クラスoracle.sql.BLOB、oracle.sql.CLOBおよびoracle.sql.NCLOB内のメソッドを使用します。これらのクラスは、BLOB、CLOBまたはNCLOBから入力ストリーム内への読取り、出力ストリームからBLOB、CLOBまたはNCLOB内への書込み、BLOB、CLOBまたはNCLOBの長さの決定およびBLOB、CLOBまたはNCLOBのクローズなど、固有の機能を提供します。

関連項目:
「LOBのデータ・インタフェース」

BFILEのストリーム

外部ファイルであるBFILEは、データベースの外部にあるファイルへのロケータを格納するために使用します。ファイルは、データ・サーバーのファイルシステム上のいずれかの場所に格納されます。ロケータは、ファイルが実際に格納された場所を指します。

問合せにより1つ以上のBFILE列をフェッチすると、JDBCドライバは必要に応じてファイルをクライアントに転送します。データにはストリームとしてアクセスできます。JDBCからBFILEデータを操作するには、Oracle拡張クラスoracle.sql.BFILEのメソッドを使用します。このクラスは、BFILEから入力ストリームへの読取り、出力ストリームからBFILEへの書込み、BFILEの長さの判定、BFILEのクローズなど、特定の機能を提供します。

データ・ストリームと複数列

1つの問合せが複数の列をフェッチする場合、その列の1つにデータ・ストリームが含まれていると、ストリーム列に後続する列の内容はストリームが読み取られるまで利用できず、後続する列が読み取られると、ストリーム列はそれ以降利用できません。ストリーミング列の先にある列を読み取ろうとすると、ストリーミング列はクローズされます。

関連項目:
「ストリーム・データを使用する際の注意」

複数列によるストリーミングの例

次のコードについて検討します。

ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
//get the date data
java.sql.Date date = rset.getDate(1);

// get the streaming data
InputStream is = rset.getAsciiStream(2);

// Open a file to store the gif data
FileOutputStream file = new FileOutputStream ("ascii.dat");

// Loop, reading from the ascii stream and
// write to the file
int chunk;
while ((chunk = is.read ()) != -1)
file.write(chunk);
// Close the file
file.close();

//get the number column data
int n = rset.getInt(3);
}

各行の受信データは、次の形式になります。

<a date><the characters of the long column><a number>

結果セットの各行を処理するときには、数値列を読み取る前にストリーム列の処理を完了する必要があります。

ヒント:
「LOBおよび外部ファイルのストリーム」

ストリーム・データ列のバイパス

ストリーム・データを含む列の読取りを回避することが望ましい場合があります。このようなデータの読取りを回避するには、ストリーム・オブジェクトのcloseメソッドをコールします。このメソッドを使用すると、ストリーム・データが廃棄され、ドライバが、ストリーム・データを含んだ列以降の非ストリーム・データを含んだ列すべてからデータを継続して読み取ることが可能になります。意図的にストリームを廃棄する場合でも、SELECT文で指定した順序で列を取り出すことは、よいプログラミング手法です。

次の例では、LONG列のストリーム・データを廃棄し、DATEおよびNUMBER列のデータのみをリカバリします。

ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");

while rset.next()
{
//get the date
java.sql.Date date = rset.getDate(1);

// access the stream data and discard it with close()
InputStream is = rset.getAsciiStream(2);
is.close();

// get the number column data
int n = rset.getInt(3);
}

ストリームのクローズ

ストリームから取得したデータは、closeメソッドをコールすることによりいつでも廃棄できます。不要になったストリームはクローズするのが、望ましいプログラミング手法です。

関連項目:
「ストリーム・データ列のバイパス」および「ストリーム・データを使用する際の注意」

注意:
ストリームのクローズは、LONGまたはLONG RAW列のパフォーマンスにはほとんど影響しません。データはすべて、そのままネットワーク経由で移動し、ドライバはネットワークからビットを読み取ることが必要です。

ストリームに関する注意

この項では、ストリームの使用に関して、次に示すいくつかの注意事項を説明します。

- ストリーム・データを使用する際の注意

- setBytesとsetStringの制限を回避するためのストリームの使用方法

- ストリームと行のプリフェッチ

ストリーム・データを使用する際の注意

この項では、誤ってストリーム・データを廃棄または喪失することがないよう、事前に注意する必要がある点を説明します。現行ストリームの読取り以外の、データベースと通信する任意のJDBC操作を実行すると、ドライバは自動的にストリーム・データを廃棄します。2つの共通する注意事項について説明します。

- ストリーム・データはアクセス後に使用します。
データ・ストリームを含む列からデータを取得するには、列のフェッチのみでは十分ではありません。列の内容をただちに処理する必要があります。そうしないと、次の列のフェッチ時にその内容は廃棄されます。

- SELECT文で指定した順序でストリーム列をコールします。

問合せを使用して複数列をフェッチすると、データベースは各行を、列を表すバイト・セットとして、SELECTで指定された順序で送信します。列の1つにストリーム・データが含まれる場合は、データベースは、次の列を処理する前にデータ・ストリーム全体を送信します。

SELECT文で指定した順序を使用せずにデータへアクセスする場合は、ストリーム・データを失う可能性があります。つまり、ストリーム・データ列をバイパスして次の列のデータにアクセスすると、ストリーム・データは失われます。たとえば、ストリーム・データ列からデータを読み取る前にNUMBER列のデータにアクセスしようとすると、JDBCドライバは自動的に、まずストリーミング・データを読み取り、続いて廃棄します。LONG列に大量のデータが格納されている場合、これは非常に非効率的です。

LONG列に後でアクセスしようとしても、データは使用できず、ドライバは「ストリームがクローズされています。」エラーを戻します。

次の例では、2番目の点について例証します。

ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
int n = rset.getInt(3);  // This discards the streaming data
InputStream is = rset.getAsciiStream(2);
// Raises an error: stream closed.
}

ストリームを取得して、それを使用する前にNUMBER列を取得した場合、ストリーム列はやはり自動的にクローズされます。

ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
InputStream is = rset.getAsciiStream(2); // Get the stream
int n = rset.getInt(3);
// Discards streaming data and closes the stream
}
int c = is.read(); // c is -1: no more characters to read-stream closed

setBytesとsetStringの制限を回避するためのストリームの使用方法

Oracle Database 10g以降、setBytesメソッドおよびsetStringメソッドで使用されるデータ・サイズの上限は大幅に増加されました。どのJava byte配列もsetBytesに渡すことができ、どのJava StringもsetStringに渡すことができます。データのサイズ、SQL文またはPL/SQL文および使用するドライバによって、JDBCドライバは自動的に、setBinaryStreamかsetCharacterStreamの使用、またはsetBytesForBlobかsetStringForClobの使用に切り替わります。

以前のバージョンのOracle Database、およびサーバー側内部ドライバでは一部、制限があります。

関連項目:
詳細は、「LOBのデータ・インタフェース」とリリース・ノートを参照してください。

ストリームと行のプリフェッチ

JDBCドライバがデータ・ストリームを含む列に遭遇すると、行のフェッチ・サイズは1に再設定されます。行のフェッチ・サイズは、データベースにアクセスするたびに複数行のデータを取り出すことができるOracleのパフォーマンス強化です。

13 Oracleオブジェクト型の操作

この章では、Java Database Database Connectivity(JDBC)でのユーザー定義オブジェクト型のサポートについて説明します。一般的な、弱い型指定のoracle.sql.STRUCTクラスの機能や、JDBC標準のSQLDataインタフェースまたはOracleのORADataインタフェースを実装するカスタムJavaクラスをマップする方法を説明します。

内容は次のとおりです。

- Oracleオブジェクトのマッピング

- Oracleオブジェクト用のデフォルトSTRUCTクラスの使用方法

- Oracleオブジェクト用のカスタム・オブジェクト・クラスの作成と使用方法

- オブジェクト型の継承

- JPublisherを使用したカスタム・オブジェクト・クラスの作成

- オブジェクト型の記述

関連項目:
『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』

Oracleオブジェクトのマッピング

Oracleオブジェクト型ではデータベースの複合データ構造がサポートされます。たとえば、name(CHAR型)、phoneNumber(CHAR型)およびemployeeNumber(NUMBER型)の属性を持つPerson型を定義できます。

Oracleでは、Oracleオブジェクト機能とJDBC機能が密接に統合されています。標準の汎用JDBC型を使用してOracleオブジェクトにマップすることも、カスタムJava型定義クラスを作成してマッピングをカスタマイズすることもできます。

注意:
このマニュアルでは、Oracleオブジェクトにマップするために作成するJavaクラスを、カスタムJavaクラス、または、より具体的にカスタム・オブジェクト・クラスと呼びます。これは、オブジェクト参照にマップされるJavaクラスであるカスタム参照クラスや、OracleコレクションにマップされるJavaクラスであるカスタム・コレクション・クラスに対比されるものです。

カスタム・オブジェクト・クラスは、データの読取りおよび書込みを行う標準JDBCインタフェースまたはOracle拡張機能インタフェースを実装できます。JDBCでは、Oracleオブジェクトを特定のJavaクラスのインスタンスとしてインスタンス化します。JDBCを使用してOracleオブジェクトにアクセスするには、次の2つの処理を行います。

1. Oracleオブジェクト用にJavaクラスを作成します。

2. そのクラスにデータを移入します。次の方法からどちらかを選んで行います。

- JDBCを使用して、オブジェクトをSTRUCTオブジェクトとしてインスタンス化します。

- OracleオブジェクトとJavaクラス間のマッピングを明示的に指定します。
これにはオブジェクト・データ用にJavaクラスをカスタマイズすることも含まれます。そうすることにより、ドライバが指定されたカスタム・オブジェクト・クラスのインスタンスにデータを移入できるようになります。この場合、Javaクラスにいくつかの制約が生じます。これらの制約を満たすには、JDBC標準java.sql.SQLDataインタフェースまたはOracle拡張機能oracle.sql.ORADataインタフェースを実装するようにクラスを定義します。

Oracle JPublisherユーティリティを使用して、カスタムJavaクラスを生成できます。

注意:
SQLDataインタフェースを使用する場合、弱い型指定のjava.sql.Structオブジェクトで十分な場合を除き、Java型マップを使用してSQLとJavaのマッピングを指定する必要があります。

Oracleオブジェクト用のデフォルトSTRUCTクラスの使用方法

OracleオブジェクトのSQLとJavaのマッピングを行うカスタムJavaクラスを提供しない場合、Oracle JDBCはオブジェクトをjava.sql.Structインタフェースを実装するオブジェクトとしてインスタンス化します。

実際のSQL型が不明な場合は、通常、カスタムJavaオブジェクトのかわりにSTRUCTオブジェクトを使用します。たとえば、Javaアプリケーションを、エンド・ユーザー・アプリケーションではなく、データベースの任意のオブジェクト・データを操作するツールとして使用する場合があります。データベースから選択したデータをSTRUCTオブジェクトに挿入したり、データベースにデータを挿入するためにSTRUCTオブジェクトを作成したりできます。STRUCTオブジェクトは、データをSQL形式で維持するため、データを完全に保存します。アプリケーション固有の形式による情報が不要な場合は、STRUCTオブジェクトを使用すると、データをより効率的に、より正確に保存できます。

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

- STRUCTオブジェクトと属性の取出し

- STRUCTオブジェクトの作成

- STRUCTオブジェクトの文へのバインド

- STRUCT自動属性バッファリング

STRUCTクラス機能

この項では、標準メソッドの機能とoracle.sql.STRUCTのOracle固有の機能を対比させて説明します。また、STRUCT記述子を説明し、STRUCTクラスのメソッド一覧を示すことにより、機能の概要を示します。

標準java.sql.Structメソッド

コードを標準JDBC 2.0に準拠させる必要がある場合、java.sql.Structインスタンスを使用し、次の標準メソッドを使用します。

- getAttributes(map)
このメソッドは、構造化オブジェクト型である属性のインスタンス化に使用するJavaクラスを決定するために、指定した型マップのエントリを使用して、属性の値を取得します。他の属性値のJava型は、基礎となるSQL型のデータに対するgetObjectコールの場合と同じです。

- getAttributes
このメソッドは、前述のgetAttributes(map)メソッドと同じですが、接続にはデフォルト型マップが使用されます。

- getSQLTypeName
このメソッドは、このStructが表すOracleオブジェクト型の完全修飾名を表すJava Stringを戻します。

STRUCTオブジェクトと属性の取出し

この項では、Oracle固有の機能またはJDBC 2.0標準機能を使用して、Oracleオブジェクトとその属性を取り出し、操作する方法を説明します。

注意:
JDBCドライバは、埋込みオブジェクト(つまり、STRUCTオブジェクトの属性であるSTRUCTオブジェクト)を、通常のオブジェクトの場合と同様に、シームレスに処理します。オブジェクトである属性を取り出すJDBCドライバは、同じ変換規則に従って、型マップ(使用可能な場合)またはデフォルトのマッピングを使用します。

java.sql.StructオブジェクトとしてのOracleオブジェクトの取出し

前述の例では、getObjectなどの標準JDBC機能を使用して、データベースからOracleオブジェクトをjava.sql.Structのインスタンスとして取り出すこともできます。getObjectによってjava.lang.Objectが戻されるため、メソッドの出力はStructにキャストする必要があります。たとえば、次のようになります。

ResultSet rs= stmt.executeQuery("SELECT * FROM struct_table");
java.sql.Struct jdbcStruct = (java.sql.Struct)rs.getObject(1);

oracle.sql型としての属性の取出し

STRUCTインスタンスまたはStructインスタンスからoracle.sql型としてOracleオブジェクト属性を取り出すには、次のように、oracle.sql.STRUCTクラスのgetOracleAttributesメソッドを使用します。

oracle.sql.Datum[] attrs = oracleSTRUCT.getOracleAttributes();

または

oracle.sql.Datum[] attrs = ((oracle.sql.STRUCT)jdbcStruct).getOracleAttributes();

標準Java型としての属性の取出し

STRUCTまたはStructインスタンスから標準Java型としてOracleオブジェクト属性を取り出すには、次のように標準getAttributesメソッドを使用します。

Object[] attrs = jdbcStruct.getAttributes();

注意:
Oracle JDBCドライバは、配列および構造の記述子をキャッシュします。そのためパフォーマンスは大きく向上します。ただし、データベース内で構造型の基礎となる型定義を変更すると、その構造型のキャッシュされた記述子は古くなり、アプリケーションでSQLException例外が通知されます。

STRUCTオブジェクトの作成

STRUCTオブジェクトの作成方法の詳細は、「クラスoracle.sql.STRUCTの概要」を参照してください。

STRUCTオブジェクトの文へのバインド

oracle.sql.STRUCTオブジェクトをプリコンパイルされたSQL文またはコール可能文にバインドするには、標準setObjectメソッド(型コードを指定)を使用するか、文オブジェクトをOracle文の型にキャストしてからOracle拡張機能のsetOracleObjectメソッドを使用します。たとえば、次のようになります。

PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
STRUCT mySTRUCT = new STRUCT (...);
ps.setObject(1, mySTRUCT, Types.STRUCT);

または

PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
STRUCT mySTRUCT = new STRUCT (...);
((OraclePreparedStatement)ps).setOracleObject(1, mySTRUCT);

STRUCT自動属性バッファリング

Oracle JDBCドライバには、STRUCT属性のバッファリングを有効または無効にするためのパブリック・メソッドが用意されています。

関連項目:
「ARRAY自動要素バッファリング」

oracle.sql.STRUCTクラスには、次のメソッドが含まれます。

- public void setAutoBuffering(boolean enable)

- public boolean getAutoBuffering()

setAutoBuffering(boolean)メソッドは自動バッファリングを有効または無効にします。getAutoBufferingメソッドは、現行の自動バッファリング・モードを戻します。デフォルトでは、自動バッファリングは無効です。

Java仮想マシン(JVM)のメモリーに、ARRAYデータをオーバーフローなしに格納できると仮定し、STRUCT属性にgetAttributesメソッドとgetArrayメソッドで複数回アクセスする場合は、JDBCアプリケーションの自動バッファリングを有効にすることをお薦めします。

注意:
変換した属性をバッファリングすると、JDBCアプリケーションでは、大量のメモリーが消費されます。

自動バッファリングを有効にすると、oracle.sql.STRUCTオブジェクトでは、変換したすべての属性のローカル・コピーが保持されます。このデータは保持されるため、この情報に後でアクセスするときにはデータ・フォーマット変換処理を実行しなくて済みます。

Oracleオブジェクト用のカスタム・オブジェクト・クラスの作成と使用方法

Oracleオブジェクト用にカスタム・オブジェクト・クラスを作成する場合は、型マップのエントリを定義する必要があります。ドライバはこの型マップに従ってOracleオブジェクトに対応するカスタム・オブジェクト・クラスをインスタンス化します。

Oracleオブジェクトとその属性データからカスタム・オブジェクト・クラスのインスタンスを作成し、データを移入する方法も指定する必要があります。ドライバによって、カスタム・オブジェクト・クラスからのデータの読取り、およびカスタム・オブジェクト・クラスへのデータの移入が実行できる必要があります。また、カスタム・オブジェクト・クラスは、提供する必要があるかどうかにかかわらず、Oracleオブジェクトの属性に対応するgetXXXメソッドおよびsetXXXメソッドも提供できます。カスタム・クラスの作成とデータ移入、およびドライバの読取り/書込み機能の設定を行うには、次のインタフェースのいずれかを選択します。

- JDBC標準SQLDataインタフェース

- Oracleが提供するORADataインタフェースおよびORADataFactoryインタフェース

作成するカスタム・オブジェクト・クラスでは、これらのインタフェースのどちらかを実装する必要があります。ORADataインタフェースは、カスタム・オブジェクト・クラスに対応するカスタム参照クラスを実装するときにも使用できます。ただし、SQLDataインタフェースを使用している場合、使用できるのは、java.sql.Refやoracle.sql.REFなど、弱いJava参照型のみです。SQLDataインタフェースは、SQLオブジェクトのマッピング専用です。

たとえば、データベースにEMPLOYEEというOracleオブジェクト型があり、そのオブジェクト型にはName(CHAR型)およびEmpNum(NUMBER型)という2つの属性が設定されているとします。型マップを使用して、EMPLOYEEオブジェクトがJEmployeeというカスタム・オブジェクト・クラスにマップされるように指定します。JEmployeeクラスでは、SQLDataまたはORADataインタフェースのどちらかを実装できます。

カスタム・オブジェクト・クラスは独自に作成できますが、Oracle JPublisherユーティリティを使用して作成すると便利です。JPublisherは標準SQLDataインタフェースとOracle固有のORADataインタフェースの両方をサポートしており、どちらかを実装するクラスを生成できます。

関連項目:
「JPublisherを使用したカスタム・オブジェクト・クラスの作成」および「オブジェクト型の継承」

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

- ORADataとSQLDataの利点

- SQLDataを実装するための型マップ

- 型マップの作成とSQLData実装のマッピング定義

- SQLData実装によるデータの読取りおよび書込み

- ORADataインタフェース

- ORAData実装によるデータの読取りおよび書込み

- その他のORADataの使用方法

ORADataとSQLDataの利点

2つのインタフェースのどちらを実装するかを決定する場合は、ORADataとSQLDataの利点を考慮する必要があります。

SQLDataインタフェースは、SQLオブジェクトのマッピング専用です。ORADataインタフェースは、より柔軟性が高く、他のSQL型と同じようにSQLオブジェクトをマップし、処理をカスタマイズできます。ORADataオブジェクトは、Oracle Databaseの任意のデータ型から作成できます。これは、たとえば、JavaのRAWデータをシリアライズするときに役立ちます。

ORADataの利点

ORADataの利点は次のとおりです。

- Oracleオブジェクトの型マップ・エントリが必要ありません。

- Oracle拡張機能に対応しています。

- oracle.sql.STRUCTからORADataを作成できます。この方法は、ネイティブなJava型への変換が最小限で済むため、より効率的です。

- toDatumメソッドを使用して、ORADataオブジェクトから、対応するDatumオブジェクトを取得できます。

- これによりパフォーマンスが改善されます。ORADataは、Oracleオブジェクトを保持するためにドライバが使用する内部書式であるDatum型を直接伴って機能します。

SQLDataの利点

SQLDataはJDBC標準であるため、コードの移植が可能です。

SQLDataを実装するための型マップ

カスタム・オブジェクト・クラスでSQLDataインタフェースを使用する場合、Oracleオブジェクト型をJavaにマップする際に使用するカスタム・オブジェクト・クラスを指定する型マップ・エントリを作成する必要があります。接続オブジェクトのデフォルトの型マップか、結果セットからデータを取得するときに指定する型マップを使用できます。ResultSetインタフェースのgetObjectメソッドには、型マップの指定に使用できるシグネチャがあります。次のいずれかを使用できます。

rs.getObject(int columnIndex);

rs.getObject(int columnIndex, Map map);

関連項目:
「Oracleオブジェクト用のカスタム・オブジェクト・クラスの作成と使用方法」

SQLData実装を使用する場合、型マップ・エントリを含めないと、オブジェクトはデフォルトでoracle.sql.STRUCTクラスにマップされます。これに対し、ORAData実装には独自のマッピング機能があるため、型マップ・エントリが必要ありません。ORAData実装を使用する場合は、標準getObjectメソッドではなく、Oracle getORADataメソッドを使用します。

型マップを使用して、JavaクラスをOracleオブジェクトのSQL型名に関連付けます。このマップは1対1のマッピングで、ハッシュ表にキーワードと値のペアとして格納されます。Oracleオブジェクトからデータを読み取ると、JDBCドライバでは、型マップが参照され、Oracleオブジェクト型のデータのインスタンス化に使用されるJavaクラスが決定されます。Oracleオブジェクトにデータを書き込むと、JDBCドライバによって、SQLDataインタフェースのgetSQLTypeNameメソッドがコールされ、JavaクラスのSQL型名が取り出されます。SQLとJava間の実際の変換は、ドライバにより実行されます。

Oracleオブジェクトに対応しているJavaクラスの属性では、ネイティブなJava型またはOracleネイティブ型を使用して属性を格納できます。

型マップの作成とSQLData実装のマッピング定義

SQLData実装を使用する場合、型マップを提供するのは、JDBCアプリケーション・プログラマの役割です。型マップは、標準のjava.util.Mapインタフェースを実装するクラスのインスタンスにする必要があります。

独自のクラスも作成できますが、標準のjava.util.Hashtableクラスが要件を満たしています。

型マップに使用するHashtableなどのクラスは、putメソッドを実装します。このメソッドは、キーワードと値のペアを入力として取ります。各キーは完全修飾SQL型名で、対応する値は指定されたJavaクラスのインスタンスです。

型マップは、接続インスタンスに関連付けられます。標準java.sql.ConnectionインタフェースとOracle固有oracle.jdbc.OracleConnectionクラスには、getTypeMapメソッドが含まれています。両方ともMapオブジェクトを戻します。

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

- 既存の型マップへのエントリの追加

- 新しい型マップの作成

- 型マップで指定されていないオブジェクト型のインスタンス化

既存の型マップへのエントリの追加

最初に接続インスタンスが確立されたときには、デフォルト型マップは空です。デフォルト型マップにデータを移入する必要があります。

既存の型マップにエントリを追加するには、次の手順を実行してください。

1. OracleConnectionオブジェクトのgetTypeMapメソッドを使用して、接続の型マップ・オブジェクトを戻します。getTypeMapメソッドはjava.util.Mapオブジェクトを戻します。たとえば、OracleConnectionインスタンスoraconnがあるとします。

java.util.Map myMap = oraconn.getTypeMap();

注意:
OracleConnectionインスタンスの型マップが初期化されていないと、getTypeMapを最初にコールしたとき、空のマップが戻されます。

2. 型マップのputメソッドを使用して、マップ・エントリを追加します。putメソッドでは2つの引数、つまり、SQL型名文字列およびそのSQL型をマップするJavaクラスのインスタンスを指定します。

myMap.put(sqlTypeName, classObject);

sqlTypeNameは、データベースのSQL型名の完全修飾名を表す文字列です。classObjectは、そのSQL型をマップするJavaクラス・オブジェクトです。次のようにClass.forNameメソッドを使用して、クラス・オブジェクトを取り出します。

myMap.put(sqlTypeName, Class.forName(className));

たとえば、CORPORATEデータベース・スキーマにPERSON SQLデータ型が定義されている場合は、そのSQLデータ型を、次の文でPersonとして定義されたPERSON Javaクラスにマップできます。

myMap.put("CORPORATE.PERSON", Class.forName("Person"));
oraconn.setTypeMap(newMap);

マップには、CORPORATEデータベースのPERSON SQLデータ型がPerson Javaクラスにマップされているエントリがあります。

注意:
型マップのSQL型名は、Oracle Databaseに大文字で格納されているので、すべて大文字にする必要があります。

新しい型マップの作成

新しい型マップを作成するには、次の一般的な手順を実行します。この例ではjava.util.Hashtableのインスタンスを使用しています。このインスタンスはjava.util.Dictionaryを拡張したもので、java.util.Mapを実装しています。

1. 新しい型マップ・オブジェクトを作成します。

Hashtable newMap = new Hashtable();

2. 型マップ・オブジェクトのputメソッドを使用して、マップにエントリを追加します。たとえば、CORPORATEデータベースにEMPLOYEEというSQL型が定義されている場合は、次のように、そのSQL型をEmployee.javaに定義されているEmployeeクラス・オブジェクトにマップできます。

newMap.put("CORPORATE.EMPLOYEE", class.forName("Employee"));

3. エントリをマップに追加した後に、OracleConnectionオブジェクトのsetTypeMapメソッドを使用して、接続の既存の型マップを上書きする必要があります。たとえば、次のようになります。

oraconn.setTypeMap(newMap);

この例では、setTypeMapメソッドによってoraconn接続オブジェクトの元のマップがnewMapに上書きされます。

注意:
接続インスタンスのデフォルト型マップは、マッピングが必要なときに、マップ名を指定しないと使用されます。たとえば、入力としてマップを指定せずに、結果セットのgetObjectをコールしたときに使用されます。

型マップで指定されていないオブジェクト型のインスタンス化

getObjectコールを使用するときに、適切なエントリを持つ型マップを指定しないと、JDBCドライバはoracle.sql.STRUCTクラスのインスタンスとしてOracleオブジェクトをインスタンス化します。Oracleオブジェクト型に埋込みオブジェクトが格納されていて、それらのオブジェクトが型マップに存在しない場合、ドライバは埋込みオブジェクトもoracle.sql.STRUCTのインスタンスとしてインスタンス化します。埋込みオブジェクトが型マップに存在する場合、getAttributesメソッドをコールすると、埋込みオブジェクトは型マップで指定されたJavaクラスのインスタンスとして戻されます。

SQLData実装によるデータの読取りおよび書込み

この項では、Oracleオブジェクトに対応するJavaクラスがSQLDataを実装している場合に、そのOracleオブジェクトに対してデータの読取りまたは書込みを行う方法について説明します。

結果セットからのSQLDataオブジェクトの読取り

ここでは、カスタム・オブジェクト・クラスに対してSQLData実装を選択したときに、OracleオブジェクトのデータをJavaアプリケーションに読み取る手順について説明します。

この手順では、すでにOracleオブジェクト型を定義し、対応するカスタム・オブジェクト・クラスを作成し、OracleオブジェクトとJavaクラス間のマッピングを定義する型マップを更新し、文オブジェクトstmtを定義しているものとします。

1. データベースに問合せを行い、OracleオブジェクトをJDBC結果セットに読み取ります。

ResultSet rs = stmt.executeQuery("SELECT emp_col FROM personnel");

表PERSONNELには、SQL型EMP_OBJECTのEMP_COLという列が1つ含まれています。このSQL型は、JavaクラスEmployeeにマップされるように、型マップに定義されています。

2. 結果セットのgetObjectメソッドを使用して、カスタム・オブジェクト・クラスのインスタンスに結果セットの1行からデータを移入します。型マップにはEmployeeのエントリが含まれるため、getObject メソッドによりユーザー定義のSQLDataオブジェクトが戻されます。

if (rs.next())
Employee emp = (Employee)rs.getObject(1);

型マップにオブジェクトのエントリが存在しない場合は、getObjectによりoracle.sql.STRUCTオブジェクトが戻されます。getObjectメソッド・シグネチャによって、汎用のjava.lang.Object型が戻されるため、出力をSTRUCT型にキャストする必要があります。

if (rs.next())
STRUCT empstruct = (STRUCT)rs.getObject(1);

getObjectメソッドがreadSQLをコールすると、SQLDataインタフェースからreadXXXがコールされます。

注意:
定義済の型マップを使用しないようにするには、getSTRUCTメソッドを使用します。このメソッドでは、型マップにマッピング・エントリが定義されている場合でも、常にSTRUCTオブジェクトが戻されます。

3. カスタム・オブジェクト・クラスにgetメソッドが定義されている場合、このメソッドを使用して、オブジェクト属性のデータを読み取ります。たとえば、EMPLOYEEに、CHAR型の属性EmpNameおよびNUMBER型の属性EmpNumがある場合は、Java Stringを戻すgetEmpNameメソッドおよびint値を戻すgetEmpNumメソッドを指定します。次に、Javaアプリケーションでこれらのメソッドを次の方法でコールします。

String empname = emp.getEmpName();
int empnumber = emp.getEmpNum();

コール可能文OUTパラメータからのSQLDataオブジェクトの取出し

PL/SQLファンクションGETEMPLOYEEをコールするCallableStatementインスタンスcsについて考えてみます。このファンクションには、プログラムによって従業員番号が渡されます。そのファンクションから対応するEmployeeオブジェクトが戻されます。このオブジェクトを取り出すには、次の手順を実行します。

1. GETEMPLOYEEファンクションをコールするCallableStatementを次のように準備します。

CallableStatement ocs = conn.prepareCall("{ ? = call GETEMPLOYEE(?) }");

2. empnumberを、GETEMPLOYEEの入力パラメータとして宣言します。SQLDataオブジェクトを、型コードOracleTypes.STRUCTを指定してOUTパラメータとして登録します。次に、文を実行します。次のように実行します。

cs.setInt(2, empnumber);
cs.registerOutParameter(1, OracleTypes.STRUCT, "EMP_OBJECT");
cs.execute();

3. getObjectメソッドを使用して、employeeオブジェクトを取り出します。

Employee emp = (Employee)cs.getObject(1);

型マップ・エントリが存在しない場合、getObjectはjava.sql.Structオブジェクトを戻します。

Struct emp = cs.getObject(1);

SQLDataオブジェクトのINパラメータとしてのコール可能文への引渡し

EmployeeオブジェクトをINパラメータとして取り、そのオブジェクトをPERSONNEL表に追加するPL/SQLファンクションaddEmployee(?)があると仮定します。この例のempは、有効なEmployeeオブジェクトです。

1. addEmployee(?)ファンクションをコールするためにCallableStatementを準備します。

CallableStatement cs =
conn.prepareCall("{ call addEmployee(?) }");

2. setObjectを使用して、empオブジェクトをINパラメータとしてコール可能文に渡します。次に、文をコールします。

cs.setObject(1, emp);
cs.execute();

SQLData実装を使用したデータのOracleオブジェクトへの書込み

ここでは、カスタム・オブジェクト・クラスに対してSQLData実装を選択したときに、JavaアプリケーションのデータをOracleオブジェクトに書き込む手順について説明します。

ここでは、あらかじめOracleオブジェクト型を定義し、対応するJavaクラスを作成し、OracleオブジェクトとJavaクラス間のマップを定義する型マップを更新していることを前提としています。

1. カスタム・オブジェクト・クラスにsetメソッドが定義されている場合、このメソッドを使用して、アプリケーションのJava変数のデータをJavaデータ型オブジェクトの属性に書き込みます。

emp.setEmpName(empname);
emp.setEmpNum(empnumber);

2. Javaデータ型オブジェクトのデータを使用して、データベース表の行に格納されているOracleオブジェクトを更新する文を、適切に準備します。

PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO PERSONNEL VALUES (?)");

3. プリコンパイルされたSQL文のsetObjectメソッドを使用して、Javaデータ型オブジェクトをプリコンパイルされたSQL文にバインドします。

pstmt.setObject(1, emp);

4. 文を実行すると、データベースが更新されます。

pstmt.executeUpdate();

ORADataインタフェース

Javaアプリケーションで使用できるOracleオブジェクトとその属性データを作成する方法の1つに、oracle.sql.ORADataインタフェースとoracle.sql.ORADataFactoryインタフェースを実装するカスタム・オブジェクト・クラスを作成する方法があります。ORADataおよびORADataFactoryインタフェースはOracleが提供するもので、JDBC標準の一部ではありません。

注意:
JPublisherユーティリティは、ORADataおよびORADataFactoryインタフェースを実装するクラスの生成をサポートしています。

ORADataの機能

ORADataインタフェースには、次の利点があります。

- 標準JDBC型に対するOracle拡張機能をサポートします。

- 作成中のJavaカスタム・クラスの名前を指定するときに、型マップは必要ありません。

- これによりパフォーマンスが改善されます。ORADataは、Oracleオブジェクトを保持するためにドライバが使用する内部書式であるDatum型を直接伴って機能します。

ORADataおよびORADataFactoryインタフェースでは、次の処理が実行されます。

- ORADataクラスのtoDatumメソッドでは、データをoracle.sql.*表現に変換します。

- ORADataFactoryでは、カスタム・オブジェクト・クラスのコンストラクタと等価のcreateメソッドが指定されます。このメソッドでは、ORADataインスタンスを作成して戻します。JDBCドライバは、createメソッドを使用して、カスタム・オブジェクト・クラスのインスタンスをJavaアプリケーションまたはアプレットに戻します。このメソッドは、入力として、oracle.sql.Datumオブジェクトと、OracleTypesクラスで指定された対応するSQL型コードを示す整数を取ります。

ORADataおよびORADataFactoryは、次のように定義されます。

public interface ORAData
{
Datum toDatum (OracleConnection conn) throws SQLException;
}

public interface ORADataFactory
{
ORAData create (Datum d, int sql_Type_Code) throws SQLException;
}

connは接続オブジェクトを、dはoracle.sql.Datum型のオブジェクトを、sql_Type_CodeはDatumオブジェクトのSQL型コードをそれぞれ表します。

オブジェクト・データの取出しと挿入

オブジェクト・データをORADataのインスタンスとして取得および挿入する場合、JDBCドライバでは次のメソッドを使用します。

オブジェクト・データは、次のいずれかの方法で取り出すことができます。

- Oracle固有OracleResultSetクラスの次のgetORADataメソッドを使用します。

ors.getORAData (int col_index, ORADataFactory factory);

このメソッドでは、結果セットのデータの列索引およびORADataFactoryインスタンスを入力として取ります。たとえば、カスタム・オブジェクト・クラスにgetORAFactoryメソッドを実装して、getORADataに入力するORADataFactoryインスタンスを作成できます。ORADataを実装するJavaクラスを使用するときは、型マップは必要ありません。

- ResultSetインタフェースで指定される標準getObject(index, map)メソッドを使用して、ORADataのインスタンスとしてデータを取り出します。この場合、指定されたオブジェクト型で使用されるファクトリ・クラスおよび対応するSQL型名を識別するには、型マップにエントリを定義する必要があります。

オブジェクト・データは、次のいずれかの方法で挿入できます。

- Oracle固有OraclePreparedStatementクラスの次のsetORADataメソッドを使用します。

ops.setORAData (int bind_index, ORAData custom_obj);

このメソッドでは、バインド変数のパラメータ索引、および変数を含むオブジェクト名を入力として取ります。

- PreparedStatementインタフェースで指定される標準setObjectメソッドを使用します。このメソッドを別のフォームで使用して、型マップなしでORADataインスタンスを挿入することもできます。

この後の項では、getORADataメソッドとsetORADataメソッドについて説明します。

OracleオブジェクトEMPLOYEEの例を引き続き使用するには、Javaアプリケーションに次のコードを記述する必要があります。

ORAData datum = ors.getORAData(1, Employee.getORAFactory());

この例では、orsはOracle結果セット、getORADataはORADataオブジェクトの取出しに使用されるOracleResultSetクラス、およびEMPLOYEEは結果セットの列1です。static Employee.getORAFactoryメソッドによって、ORADataFactoryがJDBCドライバに戻されます。JDBCドライバでは、このオブジェクトからcreate()をコールし、結果セットのデータが移入されたEmployeeクラスのインスタンスをJavaアプリケーションに戻します。

注意:

- ORADataおよびORADataFactoryは、独立したインタフェースとして定義されるため、必要に応じて異なるJavaクラスから実装できます。

- ORADataインタフェースを使用するには、カスタム・オブジェクト・クラスでoracle.sql.*をインポートする必要があります。

ORAData実装によるデータの読取りおよび書込み

この項では、対応するJavaクラスがORADataを実装する場合に、Oracleオブジェクトに対してデータの読取りまたは書込みを行う方法について説明します。

ORAData実装を使用したOracleオブジェクトからのデータの読取り

ここでは、データをOracleオブジェクトからJavaアプリケーションに読み取る手順について説明します。この手順は、ORADataを手動で実装する場合と、JPublisherを使用してカスタム・オブジェクト・クラスを作成する場合の両方に適用されます。

この手順では、すでにOracleオブジェクト型を定義し、対応するカスタム・オブジェクト・クラスを手動、またはJPublisherを使用して作成し、文オブジェクトstmtを定義しているものとします。

1. データベースに問合せを行ってOracleオブジェクトを結果セットに読み取り、Oracle結果セットにキャストします。

OracleResultSet ors = (OracleResultSet)stmt.executeQuery
("SELECT Emp_col FROM PERSONNEL");

PERSONNELは、1列の表です。列名はEmp_col、型はEmployee_objectです。

2. 結果セットのgetORADataメソッドを使用して、カスタム・オブジェクト・クラスのインスタンスに結果セットの1つの行からデータを移入します。getORADataメソッドはoracle.sql.ORADataオブジェクトを戻します。これを固有のカスタム・オブジェクト・クラスにキャストすることができます。

if (ors.next())
Employee emp = (Employee)ors.getORAData(1, Employee.getORAFactory());

または

if (ors.next())
ORAData datum = ors.getORAData(1, Employee.getORAFactory());

この例では、Employeeはカスタム・オブジェクト・クラス名、orsはOracleResultSetオブジェクト名です。

getORADataを使用しない場合、JDBCドライバでは、標準JDBC ResultSetのgetObjectメソッドを使用して、ORADataデータを取得することができます。ただし、指定されたオブジェクト型で使用されるファクトリ・クラスおよび対応するSQL型名を識別するには、型マップにエントリを定義する必要があります。

たとえば、オブジェクトのSQL型名がEMPLOYEEの場合は、対応するJavaクラスはEmployeeで、ORADataが実装されます。対応するファクトリ・クラスはEmployeeFactoryで、ORADataFactoryが実装されます。

次の文を使用して、型マップにEmployeeFactoryエントリを宣言します。

map.put ("EMPLOYEE", Class.forName ("EmployeeFactory"));

次に、getObjectの形式を使用し、マップ・オブジェクトを指定します。

Employee emp = (Employee) rs.getObject (1, map);

接続のデフォルトの型マップに、指定されたオブジェクト型と対応するSQL型名に対して使用されるファクトリ・クラスを識別するエントリがすでにある場合は、次の形式のgetObjectを使用できます。

Employee emp = (Employee) rs.getObject (1);

3. カスタム・オブジェクト・クラスにgetメソッドがある場合は、そのメソッドを使用して、オブジェクト属性のデータをアプリケーションのJava変数に読み取ります。たとえば、EMPLOYEEに、CHAR型のEmpNameおよびNUMBER型のEmpNumがある場合は、Java Stringを戻すgetEmpNameメソッドおよび整数値を戻すgetEmpNumメソッドを指定します。次に、Javaアプリケーションでこれらのメソッドを次の方法でコールします。

String empname = emp.getEmpName();
int empnumber = emp.getEmpNum();

注意:
または、コール可能文オブジェクトを使用してデータをフェッチできます。OracleCallableStatementクラスには、getORADataメソッドも定義されています。

ORAData実装を使用したデータのOracleオブジェクトへの書込み

ここでは、データをJavaアプリケーションからOracleオブジェクトに書き込む手順について説明します。この手順は、ORADataを手動で実装する場合と、JPublisherを使用してカスタム・オブジェクト・クラスを作成する場合の両方に適用されます。

この手順では、すでにOracleオブジェクト型を定義し、対応するカスタム・オブジェクト・クラスを作成しているものとします。

注意:
データベースのINSERTおよびUPDATE操作の実行時には、型マップは使用されません。

1. カスタム・オブジェクト・クラスにsetメソッドが定義されている場合、このメソッドを使用して、アプリケーションのJava変数のデータをJavaデータ型オブジェクトの属性に書き込みます。

emp.setEmpName(empname);
emp.setEmpNum(empnumber);

2. Javaデータ型オブジェクトのデータを使用して、Oracleオブジェクトを更新するプリコンパイルされたSQL文を、適切にデータベース表の行に書き込みます。

OraclePreparedStatement opstmt = conn.prepareStatement
("UPDATE PERSONNEL SET Employee = ? WHERE Employee.EmpNum = 28959);

この例では、connはConnectionオブジェクトです。

3. プリコンパイルされたSQL文のsetORADataメソッドを使用して、Javaデータ型オブジェクトをプリコンパイルされたSQL文にバインドします。

opstmt.setORAData(1, emp);

setORADataメソッドでは、カスタム・オブジェクト・クラス・インスタンスのtoDatumメソッドをコールすることにより、データベースに書き込むことができるoracle.sql.STRUCTオブジェクトが取り出されます。

この手順では、setObjectメソッドを使用してJavaデータ型をバインドすることもできます。たとえば、次のようになります。

opstmt.setObject(1,emp);

注意:
Javaデータ型オブジェクトを、INまたはOUTバインド変数として使用できます。

その他のORADataの使用方法

ORADataインタフェースには、SQLDataインタフェースより優れた柔軟性があります。SQLDataインタフェースは、Oracleオブジェクト型から目的のJava型へのマッピングをカスタマイズする目的で設計されています。SQLDataインタフェースを実装すると、JavaとSQL型間の変換が正常に終了してから、元のSQLオブジェクト・データからカスタムJavaクラス・インスタンスのフィールドへのデータ移入、およびその逆が、JDBCドライバによって実行されます。

ORADataインタフェースの場合は、Oracleオブジェクト型からJava型へのカスタマイズがサポートされるのみでなく、その場合、Javaオブジェクト型と、oracle.sqlパッケージでサポートされる任意のSQL型の間のマッピングを用意します。

このインタフェースは、oracle.sql.*型をラップするためのカスタムJavaクラスを提供したり、カスタマイズされた変換または機能を実装したりするときに役立ちます。次の使用例が考えられます。

- データの暗号化および復号化、または妥当性チェックを実行します。

- 読取りまたは書込みを行った値のロギングを実行します。

- URL情報を含む文字フィールドなどのキャラクタ列を小さなコンポーネントに解析します。

- 文字列を数値定数にマップします。

- データをより適したJava形式にマップします。たとえば、DATEフィールドをjava.util.Date形式にマップします。

- データ表現をカスタマイズします。たとえば、表の列のデータがフィート単位のとき、選択後にメートルで表現します。

- Javaオブジェクトをシリアライズおよびデシリアライズします。

たとえば、ORADataを使用すると、データベースの特定のSQLオブジェクト型に対応していないJavaオブジェクトのインスタンスを、SQL型RAWの列に格納できます。ORADataFactoryのcreateメソッドでは、oracle.sql.RAW型のオブジェクトから目的のJavaオブジェクトへの変換を実装する必要があります。ORADataのtoDatumメソッドでは、Javaオブジェクトからoracle.sql.RAW型のオブジェクトへの変換を実装する必要があります。これには、Javaのシリアライズなどを使用します。

JDBCドライバでは、データのRAWバイトをoracle.sql.RAW形式で透過的に取り出します。次に、ORADataFactoryのcreateメソッドをコールし、oracle.sql.RAWオブジェクトを目的のJavaクラスに変換します。

データベースにJavaオブジェクトを挿入するときは、そのオブジェクトをRAW型の列にバインドするのみでデータベースに格納できます。ドライバは、ORADataのtoDatumメソッドを透過的にコールして、Javaオブジェクトをoracle.sql.RAW型のオブジェクトに変換します。このオブジェクトは、データベースにRAW型の1列として格納されます。

JDBCドライバによって使用される内部書式であるoracle.sql.*書式を使用して変換が機能するように設計されているため、ORADataインタフェースのサポートは非常に効率的でもあります。さらに、型マップはSQLDataインタフェースのために必要なものであり、ORADataを実装するJavaクラスを使用する場合は不要です。

関連項目:
「ORADataインタフェース」

オブジェクト型の継承

オブジェクト型の継承により、別のオブジェクト型を拡張して新しいオブジェクト型を作成することができます。新しいオブジェクト型は、拡張元のオブジェクト型のサブタイプになります。サブタイプは、そのスーパータイプに定義されたすべての属性およびメソッドを自動的に継承します。サブタイプは、属性およびメソッドを追加し、スーパータイプから継承されたメソッドをオーバーロードまたはオーバーライドできます。

オブジェクト型の継承によって、代入可能性が導入されます。代入可能性とは、T型の任意のサブタイプに加えて、T型の値を保持するように宣言したスロットの機能です。Oracle JDBCドライバは、透過的に代入可能性を処理します。

データベース・オブジェクトは、情報が失われることなく、最も固有の型で戻されます。たとえば、STUDENT_TオブジェクトがPERSON_Tスロットに格納されている場合、Oracle JDBCドライバはSTUDENT_Tオブジェクトを表すJavaオブジェクトを戻します。

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

- サブタイプの作成

- サブタイプに対してカスタマイズされたクラスの実装

- サブタイプ・オブジェクトの取得

- サブタイプ・オブジェクトの作成

- サブタイプ・オブジェクトの送信

- サブタイプ・データ・フィールドへのアクセス

- 継承メタデータ・メソッド

サブタイプの作成

明示的にOracleオブジェクト型に対応するJavaクラスを作成するには、カスタム・オブジェクト・クラスを作成します。オブジェクト型の階層がある場合には、Javaクラスの対応する階層を作成できます。

JDBCでデータベース・サブタイプを作成する最も一般的な方法は、java.sql.Statementインタフェースのexecuteメソッドを使用して、SQLのCREATE TYPEコマンドを実行することです。たとえば、次のダイアグラムで示すように型継承階層を作成する場合があります。

図hierarchy.gifの説明

この場合、JDBCコードは次のようになります。

Statement s = conn.createStatement();
s.execute ("CREATE TYPE Person_T (SSN NUMBER, name VARCHAR2(30),
address VARCHAR2(255))");
s.execute ("CREATE TYPE Student_T UNDER Person_t (deptid NUMBER,
major VARCHAR2(100))");
s.execute ("CREATE TYPE PartTimeStudent_t UNDER Student_t (numHours NUMBER)");

次のコードでは、ST型のfooメンバー・プロシージャがオーバーロードされ、printメンバー・プロシージャによってT型から継承されたコピーが上書きされます。

CREATE TYPE T AS OBJECT (...,
MEMBER PROCEDURE foo(x NUMBER),
MEMBER PROCEDURE Print(),
...
NOT FINAL;

CREATE TYPE ST UNDER T (...,
MEMBER PROCEDURE foo(x DATE),         <-- overload "foo"
OVERRIDING MEMBER PROCEDURE Print(),   <-- override "print"
STATIC FUNCTION bar(...) ...
...
);

サブタイプを作成すると、実表の列またはオブジェクト型の属性として使用できます。

関連項目:
『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』

サブタイプに対してカスタマイズされたクラスの実装

一般に、カスタマイズされたJavaクラスはデータベース・オブジェクト・タイプを表します。サブタイプに対してカスタマイズされたJavaクラスを作成するときには、Javaクラスでデータベース・オブジェクト・タイプの階層をミラー化するかどうかを選択できます。

クラスの作成には、ORADataまたはSQLDataソリューションのいずれかを使用して、オブジェクト型の階層をマップできます。

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

- ORADataを使用した型継承階層の作成

- SQLDataを使用した型継承階層の作成

- JPublisherユーティリティ

ORADataを使用した型継承階層の作成

oracle.sql.ORADataインタフェースを実装するJavaクラスを使用した、カスタマイズされたマッピングを使用することをお薦めします。ORADataのマッピングでは、JDBCアプリケーションがORADataおよびORADataFactoryインタフェースを実装する必要があります。ORADataFactoryインタフェースを実装するクラスは、オブジェクトを作成するファクトリを格納します。各オブジェクトはそれぞれ1つのデータベース・オブジェクトを表します。

ORADataインタフェースを実装するクラスの階層は、データベース・オブジェクト・タイプ階層をミラー化できます。たとえば、PERSON_TおよびSTUDENT_Tに対するJavaクラスのマッピングは、次のようになります。

ORADataを使用したPerson_java

次のコードは、ORADataおよびORADataFactoryインタフェースを実装するPerson_javaクラスを示します。

class Person implements ORAData, ORADataFactory
{
static final Person _personFactory = new Person();

public NUMBER ssn;
public CHAR name;
public CHAR address;

public static ORADataFactory getORADataFactory()
{
return _personFactory;
}

public Person () {}

public Person(NUMBER ssn, CHAR name, CHAR address)
{
this.ssn = ssn;
this.name = name;
this.address = address;
}

public Datum toDatum(OracleConnection c) throws SQLException
{
StructDescriptor sd =
StructDescriptor.createDescriptor("SCOTT.PERSON_T", c);
Object [] attributes = { ssn, name, address };
return new STRUCT(sd, c, attributes);
}

public ORAData create(Datum d, int sqlType) throws SQLException
{
if (d == null) return null;
Object [] attributes = ((STRUCT) d).getOracleAttributes();
return new Person((NUMBER) attributes[0],
(CHAR) attributes[1],
(CHAR) attributes[2]);
}
}

Person.javaを拡張するStudent.java

次のコードは、Person.javaクラスを拡張するStudent.javaクラスを示します。

class Student extends Person
{
static final Student _studentFactory = new Student ();

public NUMBER deptid;
public CHAR major;

public static ORADataFactory getORADataFactory()
{
return _studentFactory;
}

public Student () {}

public Student (NUMBER ssn, CHAR name, CHAR address,
NUMBER deptid, CHAR major)
{
super (ssn, name, address);
this.deptid = deptid;
this.major = major;
}

public Datum toDatum(OracleConnection c) throws SQLException
{
StructDescriptor sd =
StructDescriptor.createDescriptor("SCOTT.STUDENT_T", c);
Object [] attributes = { ssn, name, address, deptid, major };
return new STRUCT(sd, c, attributes);
}

public CustomDatum create(Datum d, int sqlType) throws SQLException
{
if (d == null) return null;
Object [] attributes = ((STRUCT) d).getOracleAttributes();
return new Student((NUMBER) attributes[0],
(CHAR) attributes[1],
(CHAR) attributes[2],
(NUMBER) attributes[3],
(CHAR) attributes[4]);
}
}

ORADataインタフェースを実装するカスタマイズされたクラスでは、必ずしもオブジェクト型階層をミラー化する必要はありません。たとえば、スーパークラスを指定せずにStudentクラスを宣言できます。この場合、Studentには、PERSON_Tから継承された属性およびSTUDENT_Tによって宣言された属性を保持するフィールドが含まれます。

ORADataFactoryの実装

次の例に示すように、JDBCアプリケーションでは、データベースの問合せにファクトリ・クラスを使用して、Personまたはそのサブクラスのインスタンスを戻します。

ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
Object s = rset.getORAData (1, PersonFactory.getORADataFactory());
...
}

ORADataFactoryインタフェースを実装したクラスでは、関連付けられたカスタム・オブジェクト型のインスタンスおよび任意のサブタイプのインスタンス、または少なくともサポートされるすべての型のインスタンスの作成が可能になります。

次の例で、PersonFactory.getORADataFactoryメソッドは、Javaインスタンスperson、studentまたはparttimestudentを戻すことにより、PERSON_Tオブジェクト、STUDENT_TオブジェクトおよびPARTTIMESTUDENT_Tオブジェクトを処理できるファクトリを戻します。

class PersonFactory implements ORADataFactory
{
static final PersonFactory _factory = new PersonFactory ();

public static ORADataFactory getORADataFactory()
{
return _factory;
}

public ORAData create(Datum d, int sqlType) throws SQLException
{
STRUCT s = (STRUCT) d;
if (s.getSQLTypeName ().equals ("SCOTT.PERSON_T"))
return Person.getORADataFactory ().create (d, sqlType);
else if (s.getSQLTypeName ().equals ("SCOTT.STUDENT_T"))
return Student.getORADataFactory ().create(d, sqlType);
else if (s.getSQLTypeName ().equals ("SCOTT.PARTTIMESTUDENT_T"))
return ParttimeStudent.getORADataFactory ().create(d, sqlType);
else
return null;
}
}

次の例では、次のような表tabl1があることを想定しています。

CREATE TABLE tabl1 (idx NUMBER, person PERSON_T);
INSERT INTO tabl1 VALUES (1, PERSON_T (1000, 'Scott', '100 Oracle Parkway'));
INSERT INTO tabl1 VALUES (2, STUDENT_T (1001, 'Peter', '200 Oracle Parkway', 101, 'CS'));
INSERT INTO tabl1 VALUES (3, PARTTIMESTUDENT_T (1002, 'David', '300 Oracle Parkway', 102, 'EE'));

SQLDataを使用した型継承階層の作成

java.sql.SQLDataインタフェースを実装するカスタマイズされたクラスを使用すると、データベース・オブジェクト・タイプ階層をミラー化できます。サブクラスのreadSQLおよびwriteSQLメソッドは、通常、対応するスーパークラスのメソッドをコールして、そのスーパークラスの属性の読取りまたは書込みを行ってから、サブクラス属性の読取りまたは書込みを行います。たとえば、PERSON_TおよびSTUDENT_Tに対するJavaクラスのマッピングは、次のようになります。

SQLDataを使用したPerson.java

次のコードは、SQLDataインタフェースを実装するPerson.javaクラスを示します。

import java.sql.*;

public class Person implements SQLData
{
private String sql_type;
public int ssn;
public String name;
public String address;

public Person () {}

public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException
{
sql_type = typeName;
ssn = stream.readInt();
name = stream.readString();
address = stream.readString();
}

public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeInt (ssn);
stream.writeString (name);
stream.writeString (address);
}
}

Student.javaを拡張するStudent.java

次のコードは、Person.javaクラスを拡張するStudent.javaクラスを示します。

import java.sql.*;

public class Student extends Person
{
private String sql_type;
public int deptid;
public String major;

public Student () { super(); }

public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException
{
super.readSQL (stream, typeName);    // read supertype attributes
sql_type = typeName;
deptid = stream.readInt();
major = stream.readString();
}

public void writeSQL(SQLOutput stream) throws SQLException
{
super.writeSQL (stream);        // write supertype
// attributes
stream.writeInt (deptid);
stream.writeString (major);
}
}

必須ではありませんが、SQLDataインタフェースを実装するカスタマイズされたクラスでは、データベース・オブジェクト型階層のミラー化をお薦めします。たとえば、スーパークラスを指定せずにStudentクラスを宣言できます。この場合、Studentには、PERSON_Tから継承された属性およびSTUDENT_Tによって宣言された属性を保持するフィールドが含まれます。

SQLDataを使用したStudent.java

次のコードは、Person.javaクラスを拡張せずに、SQLDataインタフェースを直接実装するStudent.javaクラスを示します。

import java.sql.*;

public class Student implements SQLData
{
private String sql_type;

public int ssn;
public String name;
public String address;
public int deptid;
public String major;

public Student () {}

public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException
{
sql_type = typeName;
ssn = stream.readInt();
name = stream.readString();
address = stream.readString();
deptid = stream.readInt();
major = stream.readString();
}

public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeInt (ssn);
stream.writeString (name);
stream.writeString (address);
stream.writeInt (deptid);
stream.writeString (major);
}
}

JPublisherユーティリティ

SQLData、ORADataおよびORADataFactoryインタフェースを実装するカスタマイズされたクラスは手動で作成することも可能ですが、Oracle JPublisherを使用してクラスを自動作成することをお薦めします。Oracle JPublisherによって作成され、SQLData、ORADataおよびORADataFactoryインタフェースを実装するカスタマイズされたクラスでは、継承階層をミラー化できます。

関連項目:

- 「JPublisherを使用したカスタム・オブジェクト・クラスの作成」

- 『Oracle Database JPublisherユーザーズ・ガイド』

サブタイプ・オブジェクトの取得

一般的なJDBCアプリケーションでは、サブタイプ・オブジェクトは次のいずれかとして戻されます。

- 問合せ結果

- PL/SQL OUTパラメータ

- 型属性

サブタイプの取得には、デフォルト・マッピング、SQLDataマッピングまたはORADataマッピングのいずれかを使用できます。

デフォルト・マッピングの使用

デフォルトで、データベース・オブジェクトは、oracle.sql.STRUCTクラスのインスタンスとして戻されます。このインスタンスは、宣言された型または宣言された型のサブタイプのオブジェクトを表します。STRUCTクラスがデータベースのサブタイプ・オブジェクトを表す場合、このクラスにはそのスーパータイプの属性と、サブタイプに定義された属性が含まれます。

Oracle JDBCドライバは、最も固有の型でデータベース・オブジェクトを戻します。JDBCアプリケーションは、STRUCTクラスのgetSQLTypeNameメソッドを使用して、STRUCTオブジェクトのSQL型を判断します。次のコードを参照してください。

// tab1.person column can store PERSON_T, STUDENT_T and PARTIMESTUDENT_T objects
ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
oracle.sql.STRUCT s = (oracle.sql.STRUCT) rset.getObject(1);
if (s != null)
System.out.println (s.getSQLTypeName());    // print out the type name which
// may be SCOTT.PERSON_T, SCOTT.STUDENT_T or SCOTT.PARTTIMESTUDENT_T
}

SQLDataマッピングの使用

SQLDataマッピングの場合、JDBCドライバはSQLDataインタフェースを実装するクラスのインスタンスとして、データベース・オブジェクトを戻します。

データベース・オブジェクトの取得にSQLDataマッピングを使用するには、次の操作を実行します。

1. 目的のオブジェクト型のSQLDataインタフェースを実装するコンテナ・クラスを実装します。

2. 接続型マップに各Oracleオブジェクト型に対応するカスタムJava型を指定するエントリが移入されます。

3. SQLオブジェクト値へのアクセスには、getObjectメソッドを使用します。
JDBCドライバによって、型マップと一致するエントリがチェックされます。一致するエントリが見つかると、ドライバはSQLDataインタフェースを実装するクラスのインスタンスとしてデータベース・オブジェクトを戻します。

次のコードは、カスタマイズされたSQLDataマッピングの全プロセスを示します。

// The JDBC application developer implements Person.java for PERSON_T,
// Student.java for STUDENT_T
// and ParttimeStudent.java for PARTTIMESTUDEN_T.

Connection conn = ...;  // make a JDBC connection

// obtains the connection typemap
java.util.Map map = conn.getTypeMap ();

// populate the type map
map.put ("SCOTT.PERSON_T", Class.forName ("Person"));
map.put ("SCOTT.STUDENT_T", Class.forName ("Student"));
map.put ("SCOTT.PARTTIMESTUDENT_T", Class.forName ("ParttimeStudent"));

// tab1.person column can store PERSON_T, STUDENT_T and PARTTIMESTUDENT_T objects
ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
// "s" is instance of Person, Student or ParttimeStudent
Object s = rset.getObject(1);

if (s != null)
{
if (s instanceof Person)
System.out.println ("This is a Person");
else if (s instanceof Student)
System.out.println ("This is a Student");
else if (s instanceof ParttimeStudent)
System.out.pritnln ("This is a PartimeStudent");
else
System.out.println ("Unknown type");
}
}

JDBCドライバにより、各コールの接続型マップと次のものが照合されます。

- java.sql.ResultSetおよびjava.sql.CallableStatementインタフェースのgetObjectメソッド

- java.sql.StructインタフェースのgetAttributeメソッド

- java.sql.ArrayインタフェースのgetArrayメソッド

- oracle.sql.REFインタフェースのgetValueメソッド

ORADataマッピングの使用

ORADataマッピングの場合、JDBCドライバはORADataインタフェースを実装するクラスのインスタンスとして、データベース・オブジェクトを戻します。

Oracle JDBCドライバは、Oracleオブジェクト型に対するJavaクラスのマッピングを認識する必要があります。Oracle JDBCドライバにこの情報を通知するには、次の2つの方法があります。

- JDBCアプリケーションは、getORAData(int idx, ORADataFactory f)メソッドを使用して、データベース・オブジェクトにアクセスします。getORADataメソッドの2番目のパラメータは、カスタマイズされたクラスを作成するファクトリ・クラスのインスタンスを指定します。getORADataメソッドは、OracleResultSetおよびOracleCallableStatementクラスで使用可能です。

- JDBCアプリケーションは、接続型マップに各Oracleオブジェクト型に対応するカスタムJava型を指定するエントリを移入します。Oracleオブジェクト値へのアクセスには、getObjectメソッドが使用されます。

2番目の方法では、標準getObjectメソッドが使用されます。次のサンプル・コードは、最初の方法を示します。

// tab1.person column can store both PERSON_T and STUDENT_T objects
ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
Object s = rset.getORAData (1, PersonFactory.getORADataFactory());
if (s != null)
{
if (s instanceof Person)
System.out.println ("This is a Person");
else if (s instanceof Student)
System.out.println ("This is a Student");
else if (s instanceof ParttimeStudent)
System.out.pritnln ("This is a PartimeStudent");
else
System.out.println ("Unknown type");
}
}

サブタイプ・オブジェクトの作成

JDBCアプリケーションが、JDBCドライバを持つデータベース・サブタイプ・オブジェクトを作成する場合があります。これらのオブジェクトは、バインド変数としてデータベースに送られるか、JDBCアプリケーション内での情報交換に使用されます。

カスタマイズされたマッピングの場合、JDBCアプリケーションは、開発者が選択した方法に応じて、データベース・サブタイプ・オブジェクトを表すSQLDataまたはORADataベースのオブジェクトを作成します。デフォルト・マッピングの場合、データベース・サブタイプ・オブジェクトを表すSTRUCTオブジェクトを作成します。スーパータイプから継承されたすべてのデータ・フィールド、およびサブタイプに定義されたすべてのフィールドに値が必要になります。次のコードを参照してください。

Connection conn = ...   // make a JDBC connection
StructDescriptor desc = StructDescriptor.createDescriptor ("SCOTT.PARTTIMESTUDENT", conn);
Object[] attrs = {
new Integer(1234), "Scott", "500 Oracle Parkway", // data fields defined in
// PERSON_T
new Integer(102), "CS",                           // data fields defined in
// STUDENT_T
new Integer(4)                                    // data fields defined in
// PARTTIMESTUDENT_T
};
STRUCT s = new STRUCT (desc, conn, attrs);

sは、PERSON_TとSTUDENT_Tから継承したデータ・フィールドおよびPARTTIMESTUDENT_Tで定義されているデータ・フィールドを使用して初期化されます。

サブタイプ・オブジェクトの送信

一般的なJDBCアプリケーションでは、データベース・オブジェクトを表すJavaオブジェクトは次のいずれかとしてデータベースに送られます。

- データ操作言語(DML)バインド変数

- PL/SQL INパラメータ

- オブジェクト型属性値

Javaオブジェクトは、STRUCTクラスのインスタンス、またはSQLDataまたはORADataインタフェースを実装するクラスのインスタンスです。Oracle JDBCドライバは、データベースのSQLエンジンが認識できるシリアライズされた形式にJavaオブジェクトを変換します。サブタイプ・オブジェクトは、標準のオブジェクトの場合と同じ方法でバインドされます。

サブタイプ・データ・フィールドへのアクセス

サブタイプ・データ・フィールドにアクセスするためのロジックはカスタマイズされたクラスの一部ですが、デフォルト・マッピングではこのロジックはJDBCアプリケーションそのものに定義されます。データベース・オブジェクトは、oracle.sql.STRUCTクラスのインスタンスとして戻されます。JDBCアプリケーションは、STRUCTクラスの次のいずれかのアクセス・メソッドをコールして、データ・フィールドにアクセスする必要があります。

- Object[] getAttribute()

- oracle.sql.Datum[] getOracleAttribute()

getAttributeメソッドのサブタイプ・データ・フィールド

java.sql.StructインタフェースのgetAttributeメソッドは、JDBC 2.0で、オブジェクトのデータ・フィールドにアクセスするために使用されます。このメソッドはjava.lang.Object配列を戻します。ここで、各配列要素はオブジェクト属性を表します。個々の要素型は、JDBC変換マトリックス内の対応する属性型を参照することで確認できます。たとえば、SQL NUMBER属性はjava.math.BigDecimalオブジェクトに変換されます。getAttributeメソッドは、オブジェクト型のスーパータイプで定義されるすべてのデータ・フィールドと、サブタイプで定義されるデータ・フィールドを戻します。最初にスーパータイプのデータ・フィールドがリストされ、次にサブタイプのデータ・フィールドがリストされます。

getOracleAttributeメソッドのサブタイプ・データ・フィールド

getOracleAttributeメソッドはOracleの拡張機能メソッドで、getAttributeメソッドよりも効率的です。getOracleAttributeメソッドは、データ・フィールドを保持するoracle.sql.Datum配列を戻します。oracle.sql.Datum配列の各要素は属性を表します。個々の要素型は、Oracle変換マトリックス内の対応する属性型を参照することで確認できます。たとえば、SQL NUMBER属性はoracle.sql.NUMBERオブジェクトに変換されます。getOracleAttributeメソッドは、そのオブジェクト型のスーパータイプに定義されたすべての属性と、そのサブタイプに定義された属性を戻します。最初にスーパータイプのデータ・フィールドがリストされ、次にサブタイプのデータ・フィールドがリストされます。

次のコードは、getAttributeメソッドの使用方法を示します。

// tab1.person column can store PERSON_T, STUDENT_T and PARTIMESTUDENT_T objects
ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
oracle.sql.STRUCT s = (oracle.sql.STRUCT) rset.getObject(1);
if (s != null)
{
String sqlname = s.getSQLTypeName();

Object[] attrs = s.getAttribute();

if (sqlname.equals ("SCOTT.PERSON")
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
}
else if (sqlname.equals ("SCOTT.STUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
}
else if (sqlname.equals ("SCOTT.PARTTIMESTUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
System.out.println ("numHours="+((BigDecimal)attrs[5]).intValue());
}
else
throw new Exception ("Invalid type name: "+sqlname);
}
}
rset.close ();
stmt.close ();
conn.close ();

継承メタデータ・メソッド

Oracle JDBCドライバでは、継承プロパティにアクセスするための一連のメタデータ・メソッドを提供します。継承メタデータ・メソッドは、oracle.sql.StructDescriptorクラスおよびoracle.jdbc.StructMetaDataクラスに定義されます。

StructMetaDataクラスは、サブタイプ属性の継承メタデータ・メソッドを提供します。StructDescriptorクラスのgetMetaDataメソッドは、その型のStructMetaDataのインスタンスを戻します。StructMetaDataクラスには、次の継承メタデータ・メソッドが含まれます。

JPublisherを使用したカスタム・オブジェクト・クラスの作成

カスタム・オブジェクト・クラスや、他の種類のカスタムJavaクラスを作成する便利な手段に、Oracle JPublisherユーティリティを使用する方法があります。これによりカスタムJavaクラスの完全な定義が生成されます。それをインスタンス化することで、Oracleオブジェクトからのデータを保持することができます。JPublisherで生成されたクラスには、データをSQLからJavaに、およびJavaからSQLに変換するメソッドと、オブジェクト属性のgetterおよびsetterメソッドが含まれます。

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

- JPublisherの機能

- JPublisher型マッピング

関連項目:
『Oracle Database JPublisherユーザーズ・ガイド』

JPublisherの機能

JPublisherを使用して、JPublisher型マッピングの設定に従ったSQLDataインタフェースまたはORADataインタフェースを実装するカスタム・オブジェクト・クラスを作成できます。

ORADataインタフェースを使用する場合は、JPublisherによって、Oracleオブジェクト型のオブジェクト参照にマップされるカスタム参照クラスも作成されます。SQLDataインタフェースを使用する場合、Jpublisherによるカスタム参照クラスの作成はありません。かわりに、標準java.sql.Refインスタンスを使用します。

その他の機能が必要な場合は、カスタム・オブジェクト・クラスをサブクラス化して、必要な機能を追加することができます。JPublisherを実行する場合、生成されたクラス名と実装するサブクラスの名前の両方を指定するためのコマンドライン・オプションがあります。SQL-Javaマッピングが正しく機能するためには、生成されたクラスの機能の一部に組み込まれサブクラス名が、JPublisherに認識される必要があります。

注意:
JPublisherで生成されたクラスをサブクラス化せずに手動で編集する方法はお薦めできません。クラスを手動で編集した後になんらかの理由によってJPublisherを再実行する場合は、変更を実装しなおす必要があります。

JPublisher型マッピング

JPublisherでは、ユーザー定義型とその属性型をSQLとJavaとの間でマップする、様々な方法が用意されています。この項では、SQL型のカテゴリおよび各カテゴリで使用可能なマップ・オプションの一覧を示します。

SQL型のカテゴリ

Jpublisherでは、SQL型が次のグループに分類されます。それぞれのグループでは、対応する次のJPublisherオプションを指定します。

- ユーザー定義型(UDT)
Oracleオブジェクト、参照およびコレクションが含まれます。JPublisher -usertypesオプションを使用して、UDTの型マッピング実装が標準SQLData実装か、Oracle固有のORAData実装かを指定します。

- 数値型
NUMBER SQL型としてデータベースに格納されるものが含まれます。JPublisher -numbertypesオプションを使用して、数値型の型マッピングを指定します。

- ラージ・オブジェクト(LOB)型
SQL型BLOBおよびCLOBが含まれます。JPublisher -lobtypesオプションを使用して、LOB型の型マッピングを指定します。

- 組込み型
前述のカテゴリに当てはまらないSQL型としてデータベースに格納されるものが含まれます。たとえば、CHAR、VARCHAR2、LONG、RAWなどがあります。JPublisher -builtintypesオプションを使用して、組込み型の型マッピングを指定します。

型マッピング・モード

JPublisherでは、次の型マッピング・モードが定義されています。このうち2つは、数値型にのみ適用されます。

- JDBCマッピング(jdbcを設定)
SQL型とネイティブなJava型間の標準デフォルト・マッピングを使用します。カスタム・オブジェクト・クラスの場合、SQLData実装を使用します。

- Oracleマッピング(oracleを設定)
対応するoracle.sql型を使用して、SQL型にマップします。カスタム・オブジェクト・クラス、参照クラスまたはコレクション・クラスの場合、ORAData実装を使用します。

- オブジェクトJDBCマッピング(objectjdbcを設定)
これは、JDBCマッピングの拡張要素です。オブジェクトJDBCマッピングでは、適切であれば、Javaプリミティブ型(int、float、doubleなど)のかわりに、標準java.langパッケージの数値オブジェクト型(java.lang.Integer、Float、Doubleなど)が使用されます。java.lang型はNULL化可能ですが、プリミティブ型はNULL化できません。

- BigDecimalマッピング(bigdecimalを設定)
java.math.BigDecimalを使用して、すべての数値属性をマップします。これは、oracle.sql.NUMBERクラスにマップせずに、大きな数値を扱う場合に適しています。

注意:
BigDecimalマッピングを使用すると、パフォーマンスが大幅に低下することがあります。

Oracleオブジェクト型からJavaへのマッピング

JPublisher -usertypesオプションを使用すると、Oracleオブジェクト型に対応するカスタムJavaクラスを実装する方法が判断されます。

- -usertypes=oracleと設定すると(デフォルト設定)、JPublisherによって、カスタム・オブジェクト・クラスに対するORAData実装が作成されます。また、対応するカスタム参照クラスのORAData実装が作成されます。

- -usertypes=jdbcと設定すると、JPublisherによって、カスタム・オブジェクト・クラスに対するSQLData実装が作成されます。カスタム参照クラスは作成されません。参照型には、java.sql.Refまたはoracle.sql.REFを使用する必要があります。

注意:
-usertypes=oracleを設定してJPublisherを使用すると、SQLコレクション型をマップするためのORAData実装を作成することもできます。
-usertypes=jdbcという設定は、SQLコレクション型をマップするには有効ではありません。SQLDataインタフェースは、Oracleオブジェクト型のマッピング専用です。

属性型からJavaへのマッピング

Oracleオブジェクト型の属性型にマッピングを指定しない場合、JPublisherは次のデフォルトを使用します。

- 数値属性型の場合、デフォルト・マッピングはオブジェクトJDBCです。

- LOB属性型の場合、デフォルト・マッピングはOracleです。

- 組込み型属性の場合、デフォルト・マッピングはJDBCです。

代替マッピングが必要な場合は、必要に応じて、属性型と必要なマッピングに対応する-numbertypes、-lobtypesおよび-builtintypesオプションを使用します。

属性型自体がOracleオブジェクト型の場合は、-usertypesの設定に従ってマップされます。

重要:
カスタム・オブジェクト・クラスに対してSQLData実装を指定し、コードを移植可能にする場合は、属性値に対して移植可能なマッピングを使用する必要があることに注意してください。数値型と組込み型のデフォルトは移植可能ですが、LOB型には-lobtypes=jdbcを指定する必要があります。

SQL型カテゴリとマッピング設定のサマリー

表13-1では、SQL型のJPublisherカテゴリ、各カテゴリで使用できるマッピング設定およびデフォルト設定を示しています。

表13-1 JPublisherのSQL型カテゴリ、サポートされる設定およびデフォルト

SQL型カテゴリ

JPublisherマップ・オプション

マッピング設定

デフォルト

UDT型

-usertypes

oracle、jdbc

oracle

数値型

-numbertypes

oracle、jdbc、objectjdbc、bigdecimal

objectjdbc

LOB型

-lobtypes

oracle、jdbc

oracle

組込み型

-builtintypes

oracle、jdbc

jdbc

オブジェクト型の記述

Oracle JDBCには、構造化オブジェクト型の属性の名前と型に関する情報を取得する機能があります。これは考え方として、結果セットから列の名前と型に関する情報を取得するのに類似しており、実際ほとんど同一のメソッドを使用します。

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

- オブジェクト・メタデータの取出し機能

- オブジェクト・メタデータを取り出す手順

オブジェクト・メタデータの取出し機能

oracle.sql.StructDescriptorクラスには、構造化オブジェクト型に関するメタデータを取り出す機能が含まれています。StructDescriptorクラスには、結果セット・オブジェクトで使用可能な標準getMetaDataメソッドと同じ機能を持つgetMetaDataメソッドがあります。このメソッドは、属性名や型など、属性情報の集合を戻します。このメソッドをStructDescriptorオブジェクトでコールして、そのStructDescriptorオブジェクトによって記述されているOracleオブジェクト型に関するメタデータを取り出します。

StructDescriptorクラスのgetMetaDataメソッドのシグネチャは、標準ResultSetインタフェースのgetMetaDataに指定されているシグネチャと同じです。シグネチャは次のとおりです。

ResultSetMetaData getMetaData() throws SQLException

ただし、このメソッドは、実際にはoracle.jdbc.StructMetaDataのインスタンスを戻します。このクラスは、標準java.sql.ResultSetMetaDataインタフェースが結果セット・メタデータのサポートを指定するのと同じ方法で、構造化オブジェクト・メタデータをサポートします。

次のメソッドもStructMetaDataでサポートされます。

String getOracleColumnClassName(int column) throws SQLException

このメソッドは、指定した属性の値を取り出すためにOracleResultSetクラスのgetOracleObjectメソッドがコールされた場合にインスタンスが作成されるoracle.sql.Datumサブクラスの完全修飾名を戻します。たとえば、oracle.sql.NUMBERが戻されます。

getOracleColumnClassNameメソッドを使用するには、getMetaDataメソッドで戻されたResultSetMetaDataオブジェクトをStructMetaDataにキャストする必要があります。

- 注意:
前述のメソッド・シグネチャのcolumnは、誤解を招く表現です。columnの値に4を指定すると、オブジェクトの4番目の属性を指すことになります。

オブジェクト・メタデータを取り出す手順

次の手順を使用して、構造化オブジェクト型のメタデータを取り出します。

1. 該当する構造化オブジェクト型を記述するStructDescriptorインスタンスを作成するか取り出します。

2. StructDescriptorインスタンスのgetMetaDataメソッドをコールします。

3. 適切なメタデータgetterメソッド(getColumnName、getColumnTypeおよびgetColumnTypeName)をコールします。

注意:
構造化オブジェクトの属性自身が構造化オブジェクトの場合、手順1から3を繰り返します。

例

次のメソッドは、構造化オブジェクト型の属性情報を取り出す方法を示します。この例には、StructDescriptorインスタンスを作成する最初の手順が含まれています。

//
// Print out the ADT's attribute names and types
//
void getAttributeInfo (Connection conn, String type_name) throws SQLException
{
// get the type descriptor
StructDescriptor desc = StructDescriptor.createDescriptor (type_name, conn);

// get type metadata
ResultSetMetaData md = desc.getMetaData ();

// get # of attrs of this type
int numAttrs = desc.length ();

// temporary buffers
String attr_name;
int attr_type;
String attr_typeName;

System.out.println ("Attributes of "+type_name+" :");
for (int i=0; i<numAttrs; i++)
{
attr_name = md.getColumnName (i+1);
attr_type = md.getColumnType (i+1);
System.out.println (" index"+(i+1)+" name="+attr_name+" type="+attr_type);

// drill down nested object
if (attrType == OracleTypes.STRUCT)
{
attr_typeName = md.getColumnTypeName (i+1);

// recursive calls to print out nested object metadata
getAttributeInfo (conn, attr_typeName);
}
}
}

14 LOBとBFILEの操作

この章では、データ・インタフェースまたはロケータ・インタフェースのいずれかを使用して、ラージ・オブジェクト(LOB)にアクセスし、操作するために、Java Database Connectivity(JDBC)を使用する方法について説明します。

以前のリリースでは、Oracle JDBCドライバには、Oracle Databaseで多くの操作を実行するために、標準JDBC型に対するOracle拡張機能が必要でした。JDBC 3.0ではOracle拡張機能を使用する必要が少なくなり、JDBC 4.0ではこの制限はほとんどなくなりました。java.sqlおよびjavax.sqlパッケージについてはJavasoft Javadocを、Oracle拡張機能の詳細はOracle JDBC Javadocを参照してください。

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

- LOBデータ型

- Oracle SecureFile

- LOBのデータ・インタフェース

- LOBロケータ・インタフェース

- 一時LOBの使用

- OpenおよびCloseメソッドによる通常のLOBのオープン

- BFILEの操作

LOBデータ型

Oracle Database 10gより前には、LOBの最大サイズが2^32バイトでした。この制限は、Oracle Database 10gで削除されており、現在の最大サイズは使用可能な物理記憶域のサイズと同じです。

関連項目:
『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』

Oracleデータベースでは、次の4つのLOBデータ型をサポートします。

- バイナリ・ラージ・オブジェクト(BLOB)
このデータ型は、非構造バイナリ・データに使用されます。

- キャラクタ・ラージ・オブジェクト(CLOB)
このデータ型は、文字データに使用されます。

- 各国語キャラクタ・ラージ・オブジェクト(NCLOB)
このデータ型は、各国語文字データに使用されます。

- BFILE
このデータ型は、データベース表領域外の、オペレーティング・システム・ファイルに格納されるラージ・バイナリ・データ・オブジェクトに使用されます。

BLOB、CLOBおよびNCLOBは、データベース表領域に永続的に格納され、これらのデータ型に対する操作はすべて、トランザクション制御の下で実行されます。

BFILEは、Oracle独自のデータ型で、3次ストレージ・デバイス(ハード・ディスク、ネットワーク・マウント・ファイルシステム、CD-ROM、PhotoCDおよびDVDなど)上のデータベース表領域外にあるデータに読取り専用アクセスが可能です。BFILEデータは、トランザクション制御下にはなく、データベース・バックアップでは保存されません。

PL/SQL言語では、LOBデータ型がサポートされ、JDBCインタフェースにより、PL/SQLのプロシージャまたはファンクションへのINパラメータの引渡しや、OUTパラメータや戻り値の取出しが可能です。PL/SQLでは、LOBを含むすべてのデータ型に値セマンティクスを使用しますが、参照セマンティクスはBFILEに対してのみです。

Oracle SecureFile

Oracle Database 11gリリース1(11.1)では、LOBのまったく新しい記憶域としてOracle SecureFilesが導入されました。

関連項目:
Oracle Database SecureFiles and Large Objects開発者ガイド

Oracle SecureFilesの次の機能は、既存のAPIを介してJDBCプログラムで透過的に使用可能です。

- SecureFile圧縮により、データを圧縮してディスク容量を節約できます。

- SecureFile暗号化では、暗号化されたデータのランダムな読取りおよび書込みを可能にする新しい暗号化ツールが導入されました。

- 重複では、Oracle Databaseの重複LOBデータが自動検出され、データを一部のみ保存することで容量が節約されます。

- LOBデータ・パス・最適化には、記憶域レイヤーの上の論理キャッシュと新しいキャッシング・モードが含まれます。

- 高いパフォーマンスの容量管理。

setLobOptionsおよびgetLobOptions APIについては『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。コール可能文を使用してJDBCからアクセスすることもできます。

Oracle SecureFilesの次の機能は、既存のAPIに対する更新により、データベース内で実装されます。

- isSecureFileメソッド

- Oracle SecureFilesのゼロコピーI/O

isSecureFileメソッド

Oracle Database 11gリリース2(11.2)から、BLOBまたはCLOBデータによりOracle SecureFile記憶域が使用されているかどうかをチェックできるようになりました。このチェックを行うには、oracle.sql.BLOBクラスまたはoracle.sql.CLOBクラスの次のメソッドを使用します。

public boolean isSecureFile() throws SQLException

このメソッドからtrueが戻された場合、データはSecureFile記憶域を使用しています。

関連項目:
Oracle Database SecureFiles and Large Objects開発者ガイド

Oracle SecureFilesのゼロコピーI/O

Oracle Database 11gリリース2(11.2)JDBCドライバの発表により、Oracle SecureFiles操作のパフォーマンスが大幅に向上しました。これは、Oracle Net Servicesで、バッファ管理を改善するためにゼロコピーI/Oフレームワークが使用されるようになったためです。

Oracle Database 11gリリース2(11.2)では、新しい接続プロパティoracle.net.useZeroCopyIOが導入されました。このプロパティは、ゼロコピーI/Oプロトコルを有効または無効にするために使用できます。この接続プロパティは、定数OracleConnection.CONNECTION_PROPERTY_THIN_NET_USE_ZERO_COPY_IOとして定義されています。ゼロコピーI/Oフレームワークを無効にする場合は、この接続プロパティの値をfalseに設定してください。この接続プロパティのデフォルト値はtrueです。

LOBのデータ・インタフェース

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

- 効率的なメカニズム

- 入力

- 出力

- CallableSatementとIN OUTパラメータ

- サイズの制限

効率的なメカニズム

Oracle 11.2ドライバでは、LOBの内容全体の書込みと読取りができる効率的なメカニズムを提供しています。これは、データ・インタフェースと呼ばれます。このデータ・インタフェースでは、標準JDBCメソッド(getStringやsetBytesなど)を使用して、LOBデータの読取りと書込みを行います。多くの場合、これによってコーディングが簡素化され、処理が速くなります。標準のjava.sql.Blob、java.sql.Clobおよびjava.sql.NClobインタフェースと異なり、これにはランダム・アクセス機能はなく、2147483648要素を超えるデータにはアクセスできません。

入力

Oracle Database 11gリリース2(11.2)では、PreparedStatementのsetBytes、setBinaryStream、setString、setCharacterStreamおよびsetAsciiStreamメソッドが、BLOB、CLOBおよびNCLOBターゲット列を処理する能力を強化するために拡張されています。

注意:
この強化は、読取り専用のBFILEデータには影響がありません。

JDBC Oracle Call Interface(OCI)とThinドライバには、byte配列やStringのサイズに制限はなく、ストリーム・ファンクションに指定された長さには、Java言語の制限を除けば、制限はありません。

注意:
Javaでは、配列サイズは正のJava intまたは2147483648要素に制限されています。

サーバー側内部ドライバについては、現在INSERT文などのSQL文の操作に4000バイトという制限があります。この制限はPL/SQL文には適用されません。INSERT文については、次のようにPL/SQLブロックにラップするという簡単な回避方法があります。

BEGIN
INSERT id, c INTO clob_tab VALUES(?,?);
END;

大量のデータに対する次のような入力モードの自動切替えは留意する必要があります。

- 次の3つの入力モードがあります。

- 直接バインディグ
このバインディングは、サイズに制限がありますが、最も効率的です。すべての入力列のデータを、サーバーに送信するデータのブロックにインラインで配置します。バッチの複数回実行を含め、すべてのデータは1回のネットワーク操作で送信されます。

- ストリーム・バインディング
このバインディングでは、データが最後に配置されます。バッチ・サイズは1つに制限され、完了に複数回のラウンドトリップが必要になる場合があります。

- LOBバインディング
このバインディングでは、一時LOBを作成し、データをLOBにコピーして、LOBロケータをバインドします。一時LOBは、実行後、自動的に解放されます。一時LOBを作成してから、LOBに書き込む操作には、複数回のラウンドトリップが必要です。ロケータの入力はバッチ処理されます。

- SQL文の場合

- setBytesおよびsetBinaryStreamメソッドでは、4001バイト未満のデータには直接バインディングを使用します。

- setBytesおよびsetBinaryStreamメソッドでは、4000バイトを超えるデータにはストリーム・バインディングを使用します。

- JDBC 4.0では、新しい形式のsetAsciiStream、setBinaryStreamおよびsetCharacterStreamメソッドが導入されました。メソッドが長さとして長い引数を取る形式では、2147483648を超える長さにはLOBバインディングを使用します。長さを指定しない形式では、常にLOBバインディングを使用します。

- setString、setCharacterStreamおよびsetAsciiStreamメソッドでは、32767文字未満のデータには直接バインディングを使用します。

- setString、setCharacterStreamおよびsetAsciiStreamメソッドでは、32766文字を超えるデータにはストリーム・バインディングを使用します。

- 新しい形式のsetCharacterStreamメソッドは、長さの引数としてlong引数を取り、JDBC 4.0では、2147483647を超える長さにLOBバインディングを使用します。長さを指定しない形式では、常にLOBバインディングを使用します。

- PL/SQL文

- setBytesおよびsetBinaryStreamメソッドでは、32767バイト未満のデータには直接バインディングを使用します。

注意:
基礎となるデータベースがOracle Databaseリリース10.xの場合、11gリリース2(11.2)JDBCドライバを使用していても、データ・サイズ制限は32512バイトです。

- setBytesおよびsetBinaryStreamメソッドでは、32766バイトを超えるデータにはLOBバインディングを使用します。

- setString、setCharacterStreamおよびsetAsciiStreamメソッドでは、データベース・キャラクタ・セットで32767バイト未満のデータには直接バインディングを使用します。

注意:
基礎となるデータベースがOracle Databaseリリース10.xの場合、11gリリース2(11.2)JDBCドライバを使用していても、データ・サイズ制限は32512バイトです。

- setString、setCharacterStreamおよびsetAsciiStreamメソッドでは、データベース・キャラクタ・セットで32766バイトを超えるデータにはLOBバインディングを使用します。

大量データの入力モードの自動切替えは、一部のプログラムに影響を与えます。以前は、32766文字を超えるString値にsetStringを使用しようとすると、ORA-17157エラーが発生していました。現在は、ターゲット・パラメータの型に応じて、文の実行中にエラーが発生する場合と、操作が成功する場合があります。

もう1つの影響は、自動切替えの結果、パラメータの型の変更に適合させるために追加のサーバー側解析が実行される場合があることです。その結果、文が繰り返し実行されてデータ・サイズが制限の上下に変動すると、パフォーマンスに影響が生じます。ストリーム・モードへの切替えはバッチ処理にも影響を与えます。

LOBへの変換の強制

oracle.jdbc.OraclePreparedStatementインタフェースにあるsetBytesForBlobおよびsetStringForClobメソッドでは、すべてのデータ・サイズにLOBバインディングを使用します。

Oracle Database 10gリリース1(10.1)のSetBigStringTryClob接続プロパティは、使用されなくなるか不要になりました。

出力

ResultSetおよびCallableStatementのgetBytes、getBinaryStream、getSting、getCharacterStreamおよびgetAsciiStreamメソッドは、BLOB、CLOBおよびBFILE列またはOUTパラメータと連係するよう拡張されています。これらのメソッドは、2147483648未満の長さのすべてのLOBに機能します。

注意:
getStringメソッドとgetNStringメソッドを使用してBLOB列値を取得することはできません。getNStringメソッドの詳細は、「JDK 1.6での各国語キャラクタ・セット用の新しいメソッド」を参照してください。

データ・インタフェースはドライバ内でのLOBロケータへのアクセスにより動作し、アプリケーション・プログラミングに対して透過的に行われます。サポートされているすべてのリリースのデータベース(Oracle Database 9.2以降)で機能します。リリース11.1以降のデータベースでは、LOBのプリフェッチを使用して、必要なデータベース・ラウンドトリップを減らすかなくすことができます。詳細は、「LOBのプリフェッチ」を参照してください。

BLOBまたはCLOBデータの読取りおよび書込みには、LONG RAWおよびLONGデータと同じストリーミング・メカニズムを使用することもできます。BFILEデータは、同じストリーミング・メカニズムを使用して読み取れます。読み取るには、列に対してdefineColumnType(nn, Types.LONGVARBINARY)またはdefineColumnType(nn,Types.LONGVARCHAR)を使用します。これによって、ダイレクト・ストリームがデータに対してLONG RAWまたはLONG列であるかのように作成されます。この技術はOracle Database 10gリリース1(10.1)以降に限定されます。

CallableSatementとIN OUTパラメータ

PL/SQLの要件は、IN OUTパラメータの入力と出力に同じJava型を使用する必要があります。この章で説明した拡張機能による型の自動切替えが原因で、これに関して問題が発生する場合があります。

ストアド・プロシージャのIN OUT CLOBパラメータがあり、このパラメータの値を設定するためにsetStringを使用するとします。INおよびOUTパラメータについて、バインドを同じ型にする必要があります。データ・サイズが判明していないかぎり、入力モードの自動切替えによって問題が発生します。たとえば、入力データおよび出力データの両方が32766バイトを超えないことが判明している場合は、入力パラメータにsetStringメソッドを使用し、OUTパラメータをTypes.VARCHARとして登録し、出力パラメータにgetStringメソッドを使用できます。

よりよい解決方法は、ストアド・プロシージャを変更してINパラメータとOUTパラメータを個別にすることです。たとえば、次のストアド・プロシージャがあったとします。

CREATE PROCEDURE clob_proc( c IN OUT CLOB );

これを次のように変更します。

CREATE PROCEDURE clob_proc( c_in IN CLOB, c_out OUT CLOB );

もう1つの回避方法は、コンテナ・ブロックを使用してコールすることです。次のようにclob_procプロシージャをJava文字列でラップすると、prepareCall文に使用できます。

"DECLARE c_temp; BEGIN c_temp := ?; clob_proc( c_temp); ? := c_temp; END;"

どちらの場合でも、最初のパラメータにsetStringメソッドを使用し、2番目のパラメータにregisterOutParameterメソッドとTypes.CLOBを使用できます。

サイズの制限

非常に大きなbyte配列またはStringが作成されるために、Javaメモリー管理システムのパフォーマンスに影響が生じることに注意してください。Java仮想マシン(JVM)ベンダーが提供する情報を参照して、大量のデータ要素がメモリー管理に与える影響を理解し、かわりにストリーム・インタフェースを使用することを検討してください。

LOBロケータ・インタフェース

ロケータは少量データ構造体で、LOBの実際のデータへのアクセスに使用できる情報が格納されます。データベース表で、ロケータは表に直接格納されるのに対し、データはその表または別の記憶域に格納できます。大型のLOBの場合は、別の表領域を使用するのが一般的です。

JDBC 4.0では、LOBは、java.sql.Blob、java.sql.Clobおよびjava.sql.NClobインタフェースを使用して読込みまたは書込みを行います。これにより、LOBのデータにはランダム・アクセスできます。

Oracle実装クラスのoracle.sql.BLOB、oracle.sql.CLOBおよびoracle.sql.NCLOBではロケータを格納し、それを使用してデータにアクセスします。oracle.sql.BLOBクラスとoracle.sql.CLOBクラスは、それぞれjava.sql.Blobインタフェースとjava.sql.Clobインタフェースを実装します。ojdbc6.jarでは、oracle.sql.NCLOBはjava.sql.NClobを実装しますが、ojdbc5.jarでは、java.sql.Clobインタフェースを実装します。

Oracle Database 11 gでは、Oracle JDBCドライバは、ojdbc6.jarではJDBC 4.0 java.sql.NClobインタフェースをサポートします。これはJDK 1.6でコンパイルし、JRE 6以上で使用する必要があります。ojdbc5.jarではJDBC 3.0標準をサポートします。これはJRE 5以上で使用する必要があります。

これに対し、oracle.sql.BFILEはOracle拡張機能で、対応するjava.sqlインタフェースはありません。

Oracle Databaseの旧リリースのoracle.sql.CLOBおよびoracle.sql.BLOBインタフェースで提供されているいくつかの読取りおよび書込みメソッドなど、一部のOracle拡張機能は、必要でなくなるか、非推奨となりました。アプリケーションを標準JDBC 3.0インタフェースに移植するか、JDK1.6以上とojdbc6.jarを使用している場合は、JDBC 4.0インタフェースに移植する必要があります。

関連項目:
詳細は、Javadocを参照してください。

LOBのプリフェッチ

Oracle Database 11gリリース2(11.2)JDBCドライバの場合、通常のフェッチ操作中にロケータとともにLOBデータの始めをプリフェッチするのと同様に、LOBの長さやチャンク・サイズなどのメタデータをプリフェッチすることで、ラウンドトリップの回数を減らします。LOB列を選択して結果セットに入れる場合、サーバーやJDBCドライバの新機能により、ロケータがフェッチされると、データの一部またはすべてをクライアントにプリフェッチできます。後続の読取りAPIコールでは、プリフェッチ・バッファからデータが取得され、データベースへのラウンドトリップは不要になります。

プリフェッチ・サイズは、BLOBの場合はバイトで、CLOBの場合は文字数で指定されます。接続プロパティoracle.jdbc.defaultLobPrefetchSizeを設定することで指定できます。このプロパティの値は、次の2つの方法でオーバーライドできます。

- 文レベル: oracle.jdbc.OracleStatement.setLobPrefetchSize(int)メソッドを使用

- 列レベル: 長さを引数として取るdefineColumnTypeメソッドの形式を使用

デフォルトのプリフェッチ・サイズは4000です。

注意:
大型LOBのプリフェッチ・サイズを、行プリフェッチ・サイズや多数のLOB列と一緒に設定するときには、予想されるメモリー消費に注意してください。

関連項目:
詳細は、Javadocを参照してください。

JDBC 4.0の新しいLOB API

Oracle Database 11gリリース1(11.1)から、新しいインタフェースjava.sql.NClobが導入されました。Oracleドライバが、ojdbc5.jarとojdbc6.jarでoracle.sql.NCLOBインタフェースを実装します。ojdbc6.jarでは、java.sql.NClobの実装が宣言され、ojdbc5.jarでは、oracle.sql.CLOBインタフェースを拡張するのみです。

Oracleドライバにより、新しいファクトリ・メソッドcreateBlob、createClobおよびcreateNClobが、一時LOBを作成するためにjava.sql.Connectionインタフェースで実装されます。

JDK 1.6から、java.sql.Blob、java.sql.Clobおよびjava.sql.NClobインタフェースに、LOBを解放し、関連付けられたリソースを解放する新しいfreeメソッドが導入されました。Oracleドライバはこのメソッドを使用して、一時LOBを解放します。

一時LOBの使用

一時LOBは、一時データの格納に使用できます。データは、通常の表領域ではなく、一時表領域に格納されます。不要になった一時LOBは解放する必要があります。解放しない場合、LOBによって使用されている一時表領域は再生されません。

一時LOBは、表に挿入できます。挿入すると、LOBの永続的なコピーが作成されて格納されます。

注意:
一時LOBを挿入する方が便利な場合があります。たとえば、LOBデータが相対的に小さい場合は、空のロケータを取り出すデータベース・ラウンドトリップのコストに比べて、データをコピーするオーバーヘッドが小さくなります。データは、最初はサーバーの一時表領域に格納され、その後永続記憶域に移されるためです。

一時LOBは、oracle.sql.BLOBクラスとoracle.sql.CLOBクラスの両方で定義されているstaticメソッドcreateTemporaryで作成します。一時LOBを解放するには、freeTemporaryメソッドを使用します。

JDBC 4.0で利用できる接続ファクトリ・メソッドを使用することにより、一時LOBを作成することもできます。詳細は、「LOBの作成」を参照してください。

isTemporaryメソッドをコールすることで、LOBが一時LOBかどうかをテストできます。LOBがcreateTemporaryメソッドをコールして作成された場合、isTemporaryメソッドは、trueを戻し、それ以外の場合はfalseを戻します。

一時LOBを解放するには、freeTemporaryメソッドをコールします。セッションまたはコールを終了する前に、一時LOBを解放してください。

注意:

- 一時LOBを解放しない場合は、データベース内でそのLOBによって使用されている記憶域を使用できないようにします。頻繁に一時LOBを解放しないと、一時表領域が使用できないLOB記憶域でいっぱいになってしまいます。

- 一時LOB列のあるReultSetからデータをフェッチする場合は、getStringまたはgetBytesのかわりに、getClobまたはgetBlobメソッドを使用してください。

- java.sql.Blob、java.sql.Clobおよびjava.sql.NClobインタフェースにあるJDBC 4.0のfreeメソッドは、freeTemporaryメソッドに優先します。

JDK 1.5でのテンポラリNCLOBの作成

各国語キャラクタ・ラージ・オブジェクト(NCLOB)はcreateTemporaryメソッドの変種を使用して作成します。

JDK 1.6でのテンポラリNCLOBの作成

JDBC 4.0ではNCLOBが直接サポートされています。java.sql.Connectionインタフェースの標準のファクトリ・メソッドを使用してNCLOBを作成することができます。

OpenおよびCloseメソッドによる通常のLOBのオープン

この項では、LOBのオープンとクローズの方法について説明します。この機能は、oracle.sql.BLOBおよびoracle.sql.CLOBインタフェースの次のメソッドを使用して、JDBC実装されます。

注意:
LOBは必ずしもオープンおよびクローズする必要はありません。パフォーマンス上の理由から、LOBのオープンとクローズを選択できます。

関連項目:
『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』

- void open (int mode)

- void close()

- boolean isOpen()

Open/Closeコール操作内部でLOB操作をラップしない場合、LOBは変更のたびに暗黙的にオープンおよびクローズされ、ドメイン索引上でトリガーが起動されます。この場合、LOBを変更するとただちに、LOBのドメイン索引がすべて更新されることに注意してください。したがって、ドメインLOB索引は常に有効となり、同じトランザクション内でいつでも使用できます。

Open/Closeコール操作の内部でLOB操作をラップすると、LOBが変更されるたびにトリガーが起動されることはありません。かわりに、Closeがコールされた時点で、ドメイン索引に関するトリガーが起動します。たとえば、closeメソッドをコールするまでドメイン索引が更新されないようにアプリケーションを設計できます。ただし、これは、LOB上のドメイン索引がOpen/Closeコールの間は無効であることを意味します。

LOBを開くには、openメソッドまたはopen(int)メソッドをコールします。その後、そのLOBに関連付けられたトリガーを起動することなく、LOBの読取りまたは書込み操作を実行できます。LOBへのアクセスが終了後、closeメソッドをコールしてLOBをクローズします。LOBをクローズすると、そのLOBに関連付けられたトリガーが起動します。

isOpenメソッドをコールすると、LOBがオープンまたはクローズしているかどうかを確認できます。open(int)メソッドをコールしてLOBをオープンした場合は、引数の値がoracle.sql.BLOBクラスおよびoracle.sql.CLOBクラスで定義されたMODE_READONLYまたはMODE_READWRITEである必要があります。MODE_READONLYを使用してLOBをオープンした場合は、そのLOBに書込みを試みるとSQL例外が発生します。

注意:

- トランザクションでオープンしたすべてのLOBをクローズする前に、そのトランザクションをコミットしようとすると、エラーが発生します。オープンしているLOBのオープン状態は破棄され、トランザクションは正常にコミットされます。このため、トランザクション内でLOBおよび非LOBデータに対して行われた変更はすべてコミットされますが、ドメイン索引に関するトリガーは確実には実行されません。

- openおよびcloseメソッドは、通常のLOBに対してのみ適用されます。closeメソッドは、一時LOBに使用されるfreeまたはfreeTemporaryメソッドとは異なります。freeおよびfreeTemporaryメソッドは、記憶域を解放し、LOBを使用不可にします。他方、closeメソッドは、LOBでの変更が完了したのでトリガーを起動し索引を更新する必要があることを、データベースに指示します。LOBは、closeメソッドへのコール後もまだ使用可能です。

BFILEの操作

この項では、ファイル・ロケータを使用してBFILEからデータを読み取る方法を説明します。この項の内容は次のとおりです。

- BFILEロケータの取出し

- BFILESへの書込み

BFILEロケータの取出し

BFILEデータ型とoracle.sql.BFILEクラスは、Oracle独自のものです。したがって、これらには標準インタフェースはありません。この型のデータには、Oracle拡張機能を使用する必要があります。

標準JDBC結果セットまたはBFILEロケータを含むコール可能文オブジェクトがある場合は、標準結果セットのgetObjectメソッドを使用して、ロケータにアクセスできます。このメソッドは、oracle.sql.BFILEオブジェクトを戻します。

また、結果セットをOracleResultSetにキャストするか、コール可能文をOracleCallableStatementにキャストし、getOracleObjectまたはgetBFILEメソッドを使用することにより、ロケータにアクセスすることもできます。

注意:
getObjectまたはgetOracleObjectメソッドを使用している場合は、必要に応じて出力をキャストしてください。

ロケータがあれば、oracle.sql.BFILE内のAPIによりBFILEデータにアクセスできます。これらのAPIは、java.sql.BLOBインタフェースの読取りメソッドに似ています。

BFILESへの書込み

BFILEの内容にデータは書き込めませんが、oracle.sql.BFILEのインスタンスをSQL文またはPL/SQLプロシージャへの入力として使用できます。これは次のいずれかを実行することで行えます。

- 標準のsetObjectメソッドを使用します。

- 文をOraclePreparedStatementまたはOracleCallableStatementにキャストし、setOracleObjectまたはsetBFILEメソッドを使用します。これらのメソッドは、パラメータ索引およびoracle.sql.BFILEオブジェクトを入力として取ります。

注意:

- BFILE用の標準java.sqlインタフェースはありません。

- getBFILEメソッドをOracleResultSetおよびOracleCallableStatementクラスで使用して、oracle.sql.BFILEオブジェクトを取り出します。OraclePreparedStatementおよびOracleCallableStatementインタフェースのsetBFILEメソッドは、引数としてoracle.sql.BFILEオブジェクトを受け入れます。これらのメソッドを使用してBFILEに書き込みます。

- getBfile、setBfileおよびupdateBfileメソッドのかわりに、getBFILE、setBFILEおよびupdateBFILEメソッドを使用することをお薦めします。たとえば、setBfileメソッドのかわりにsetBFILEメソッドを使用します。

BFILEは読取り専用です。データの本体はオペレーティング・システム(OS)のファイルシステムにあり、OSのツールとコマンドを使用しないと書き込めません。JDBCから、またはSQLを実行する別の方法を使用して、適切なSQL文を実行することにより、既存の外部ファイル用のBFILEを作成できます。しかし、BFILEが参照するOSファイルSQLまたはJDBCでは作成できません。これは、サーバー・ファイルシステムにアクセスするプロセスによって外部的にしか作成されません。

注意:

- 旧版マニュアルのこの章で示されているサンプル・コードは、OTNでダウンロードできるサンプル・コードを参照するために削除されました。

- 完全な作業プログラムは、次のリンクからdemo.zipファイルをダウンロードできます。

http://www.oracle.com/technology/tech/java/sqlj_jdbc/index.html

15 Oracleオブジェクト参照の使用

この章では、オブジェクト参照へのアクセスおよび操作を行う、標準Java Database Connectivity(JDBC)について説明します。

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

- オブジェクト参照用Oracle拡張機能

- オブジェクト参照の取出しと引渡し

- オブジェクト値に対する、オブジェクト参照を介したアクセスと更新

- JPublisherで生成するカスタム参照クラス

オブジェクト参照用Oracle拡張機能

Oracleでは、データベース・オブジェクトへの参照を使用できます。Oracle JDBCでは、次のオブジェクト参照がサポートされます。

- SELECT句の列

- INまたはOUTバインド変数

- Oracleオブジェクトの属性

- コレクション型オブジェクトの要素

SQLでは、オブジェクト参照(REF)は厳密に型指定されています。たとえば、EMPLOYEEオブジェクトへの参照は、REFのみではなく、EMPLOYEE REFとして定義されます。

オブジェクト参照を選択する場合は、オブジェクト本体でなく、オブジェクトへのポインタのみを取得することに注意してください。移植性を重視して、参照をjava.sql.Refインスタンスとしてインスタンス化するか、事前に作成したカスタムJavaクラスのインスタンスとしてインスタンス化して強い型指定の利点を取るか、両方の選択肢があります。オブジェクト参照のために使用されるカスタムJavaクラスは、カスタム参照クラスとして参照されるため、oracle.sql.ORADataインタフェースを実装する必要があります。

結果セットまたはコール可能文オブジェクトを介してREFインスタンスを取得し、プリコンパイルされたSQL文またはコール可能文オブジェクトを介して更新されたREFにインスタンスをデータベースに戻すことができます。REFクラスには、基礎となるオブジェクト属性値を取得および設定し、基礎となるオブジェクトのSQLベース型名を取得する機能があります。

カスタム参照クラスには、これと同じ機能が含まれている他に、強い型指定が適用されるという利点があります。この強い型指定により、実行時まで検出できないコーディング・エラーを、コンパイル時に発見できます。

注意:

- カスタム・オブジェクト・クラスに対してoracle.sql.ORADataインタフェースを使用する場合は、対応するカスタム参照クラスにもORADataを使用します。ただし、カスタム・オブジェクト・クラスに対して標準java.sql.SQLDataインタフェースを使用する場合、参照に使用できるのは、弱いJava型のみです。SQLDataインタフェースは、SQLオブジェクト型のマッピング専用です。

- JDBCアプリケーションでREFオブジェクトを作成して取り出すことができるのは、SQL文を実行した場合のみです。REFオブジェクトを作成して取り出すためのJDBC固有の機能はありません。

- 配列はオブジェクトの同様に構造化型ですが、参照できません。

オブジェクト参照の取出しと引渡し

この項では、オブジェクト参照の取出しと引渡しを行うJDBC機能を説明します。内容は次のとおりです。

- 結果セットからのオブジェクト参照の取出し

- オブジェクト参照のコール可能文からの取出し

- オブジェクト参照のプリコンパイルされたSQL文への引渡し

結果セットからのオブジェクト参照の取出し

オブジェクト参照を取り出す方法を示すために、次の例では、最初に、Oracleオブジェクト型ADDRESSを定義し、次にPEOPLE表でこのオブジェクト型を参照します。

create type ADDRESS as object
(street_name     VARCHAR2(30),
house_no        NUMBER);

create table PEOPLE
(col1 VARCHAR2(30),
col2 NUMBER,
col3 REF ADDRESS);

ADDRESSオブジェクト型には、street nameとhouse numberという2つの属性があります。PEOPLE表には、文字データ用の列、数値データ用の列、およびADDRESSオブジェクトへの参照を含む列が設定されています。

オブジェクト参照を取り出すには、次の手順に従ってください。

1. 標準SQL SELECT文を使用して、データベース表のREF列から参照を取り出します。

2. getRefを使用して、結果セットからAddress参照を取り出し、REFオブジェクトに格納します。

3. AddressをSQLオブジェクト型のADDRESSに対応するJavaカスタム・クラスに変換します。

4. JavaクラスAddressとSQL型ADDRESS間の対応を、型マップに追加します。

5. getObjectメソッドを使用して、Address参照の内容を取り出します。出力をAddressにキャストします。

また、PEOPLEデータベース表の定義については、この項の始めの説明を参照してください。前述の手順を実行するコードは、Addressを型マップに追加する手順を除いて、次のようになります。

ResultSet rs = stmt.executeQuery("SELECT col3 FROM PEOPLE");
while (rs.next())
{
REF ref = rs.getRef(1);
Address a = (Address)ref.getObject();
}

注意:
前述のコードで、stmtはあらかじめ定義されている文オブジェクトです。

オブジェクト参照のコール可能文からの取出し

オブジェクト参照をPL/SQLブロックのOUTパラメータとして取り出すには、OUTパラメータのバインド型を登録する必要があります。

1. 次のように、コール可能文をOracleCallableStatementにキャストします。

OracleCallableStatement ocs =
(OracleCallableStatement)conn.prepareCall("{? = call func()}");

2. 次の形式のregisterOutParameterメソッドを使用して、OUTパラメータを登録します。

ocs.registerOutParameter (int param_index, int sql_type, String sql_type_name);

param_indexはパラメータ索引、sql_typeはSQL型コードです。sql_type_nameは、この参照が使用される構造化オブジェクト型の名前です。たとえば、OUTパラメータがADDRESSオブジェクトに対する参照の場合、ADDRESSは渡されるsql_type_nameです。

3. 次のように、コールを実行します。

ocs.execute();

オブジェクト参照のプリコンパイルされたSQL文への引渡し

オブジェクト参照をプリコンパイルされたSQL文に渡す方法は、他のSQL型を渡す場合と同様です。プリコンパイルされたSQL文のオブジェクトのsetObjectメソッドまたはsetREFメソッドを使用します。

次のプリコンパイルされたSQL文を使用し、ROWIDに基づいてアドレス参照を更新します。

PreparedStatement pstmt =
conn.prepareStatement ("update PEOPLE set ADDR_REF = ? where ROWID = ?");
pstmt.setRef (1, addr_ref);
pstmt.setRowId (2, rowid);

オブジェクト値に対する、オブジェクト参照を介したアクセスと更新

RefオブジェクトのsetObjectメソッドを使用すると、データベースにあるオブジェクトの値をオブジェクト参照から更新できます。このためには、最初に、データベース・オブジェクトに対する参照を取り出し、データベース・オブジェクトに対応するJavaオブジェクトを作成する必要があります。

たとえば、次のように、「オブジェクト参照の取出しと引渡し」のコードを使用して、データベースのADDRESSオブジェクトへの参照を取り出せます。

ResultSet rs = stmt.executeQuery("SELECT col3 FROM PEOPLE");
if (rs.next())
{
Ref ref = rs.getRef(1);
Address a = (Address)ref.getObject();
}

次に、データベースのADDRESSオブジェクトに対応するJavaのAddressオブジェクトを作成できます。次のように、RefインタフェースのsetObjectメソッドを使用して、データベース・オブジェクトの値を設定します。

Address addr = new Address(...);
ref.setObject(addr);

この例では、setValueメソッドによりデータベースのADDRESSオブジェクトが即時更新されます。

JPublisherで生成するカスタム参照クラス

この章では、java.sql.Refクラスの機能を主に説明していますが、カスタムJavaクラス、より厳密にはカスタム参照クラスからも、Oracleオブジェクト参照にアクセスできます。

カスタム参照クラスには、この章でここまで説明してきたすべての機能に加え、強い型指定が適用されるという利点があります。カスタム参照クラスは、次の3つの要件を満たす必要があります。

- oracle.sql.ORADataインタフェースを実装する必要があります。カスタム・オブジェクト・クラス用の代替である標準JDBC SQLDataインタフェースは、カスタム参照クラスには使用できないので注意してください。

- コンパニオン・クラスの場合は、カスタム参照クラスのインスタンスを作成するために、oracle.sql.ORADataFactoryインタフェースを実装する必要があります。

- オブジェクト・データを参照する方法を用意する必要があります。JPublisherは、oracle.sql.REF属性を使用することにより、これを実現します。

カスタム参照クラスは独自にも作成できますが、Oracle JPublisherユーティリティを使用して作成すると便利です。JPublisherを使用して、Oracleオブジェクトにマップするためのカスタム・オブジェクト・クラスを生成し、JPublisherがORAData実装を使用するように指定した場合、JPublisherは、ORADataとORADataFactoryを実装して、oracle.sql.REF属性を含むカスタム参照クラスも生成します。JPublisher -usertypesマッピング・オプションがoracleに設定されている場合(デフォルト)、ORAData実装が使用されます。

カスタム参照クラスは、強い型指定です。たとえば、OracleオブジェクトEMPLOYEEを定義すると、JPublisherによりEmployeeカスタム・オブジェクト・クラスおよびEmployeeRefカスタム参照クラスが生成されます。汎用oracle.sql.REFインスタンスのかわりにEmployeeRefインスタンスを使用すると、実行時ではなくコンパイル時にエラーを簡単に捕捉できます。たとえば、EmployeeRef変数に別の種類のオブジェクト参照を間違えて割り当てた場合は、簡単にエラーが検出されます。

標準SQLDataインタフェースはSQLオブジェクト・マッピングのみをサポートすることに注意してください。このため、JPublisherがカスタム・オブジェクト・クラスを作成する際に標準SQLDataインタフェースを実装するように指定した場合、JPublisherはカスタム参照クラスを生成しません。この場合、唯一のオプションは、標準java.sql.Refインスタンスまたはoracle.sql.REFインスタンスを使用して、オブジェクト参照にマップすることです。

関連項目:

- 「JPublisherを使用したカスタム・オブジェクト・クラスの作成」

- 『Oracle Database JPublisherユーザーズ・ガイド』

16 Oracleコレクションの操作

この章では、Java配列とそのデータにマップされるOracleコレクションにアクセスして操作するための、標準Java Database Connectivity(JDBC)に対するOracleの拡張機能について説明します。内容は次のとおりです。

- コレクションのためのOracle拡張機能

- コレクション機能の概要

- ARRAYパフォーマンス拡張要素メソッド

- 配列の作成と使用方法

- 型マップを使用した配列要素のマップ

- JPublisherで生成するカスタム・コレクション・クラス

コレクションのためのOracle拡張機能

データベース内の変数配列(VARRAY)またはNESTED TABLEのいずれかであるOracleコレクションは、Javaでは配列にマップされます。JDBC 2.0配列は、JavaでOracleコレクションをインスタンス化するために使用されます。コレクションおよび配列という用語は、どちらも同じ意味で使用されることがあります。ただし、データベース側ではコレクション、JDBCアプリケーション側では配列のほうが適切です。

サポートされるのは、SQL型名を指定することでコレクションの型を記述できる、名前付きコレクションのみです。JDBCを使用すると、次のものに配列を使用できます。

- SELECT句の列

- INまたはOUTバインド変数

- Oracleオブジェクトの属性

- 他の配列の要素

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

- コレクションのインスタンス化に関する選択

- コレクションの作成

- マルチ・レベルのコレクション型の作成

コレクションのインスタンス化に関する選択

アプリケーションでは、弱い型指定のoracle.sql.ARRAYクラスのインスタンスとして、または事前に作成した強い型指定のカスタムJavaクラスのインスタンスとしてコレクションをインスタンス化するオプションがあります。コレクションのために使用するカスタムJavaクラスは、カスタム・コレクション・クラスと呼びます。カスタム・コレクション・クラスは、Oracleのoracle.sql.ORADataインタフェースを実装する必要があります。さらに、カスタム・クラスまたはコンパニオン・クラスは、oracle.sql.ORADataFactoryを実装する必要があります。標準java.sql.SQLDataインタフェースは、SQLオブジェクト型のマッピング専用です。

oracle.sql.ARRAYクラスは、標準のjava.sql.Arrayインタフェースを実装します。

ARRAYクラスには、配列全体を取り出し、配列要素のサブセットを取り出し、配列要素のSQLベース型名を取り出すための機能があります。ただし、setterメソッドがないため、配列に書き込むことはできません。

カスタム・コレクション・クラスを使用すると、ARRAYクラスと同様に、配列のすべてまたは一部を取得して、SQLベース型名を取得できます。強い型指定により、実行時まで検出できない可能性のあるコーディング・エラーを、コンパイル時に発見できる利点もあります。

また、JPublisherによって作成されるカスタム・コレクション・クラスは、個々にアクセス可能な要素によって、書込み可能な機能を提供します。

注意:
VARRAYへのアクセスとNESTED TABLEへのアクセス間で、コード上の違いはありません。ARRAYクラス・メソッドは、VARRAYまたはNESTED TABLEに適用されているかどうかを判断し、適切なアクションを決定して応答します。

関連項目:
カスタム・コレクション・クラスの詳細は、「JPublisherで生成するカスタム・コレクション・クラス」を参照してください。

コレクションの作成

Oracleは名前付きコレクションのみをサポートしているため、特定のVARRAY型名またはNESTED TABLE型名を制限する必要があります。VARRAYとNESTED TABLEは、型自体ではなく型のカテゴリです。

次のSQL CREATE TYPE文を使用してコレクションを作成すると、コレクションにSQL型名が割り当てられます。

CREATE TYPE <sql_type_name> AS <datatype>;

VARRAYは、サイズ可変の配列です。順序付けられたデータ要素のセットを保持し、要素はすべて同じデータ型です。各要素は、索引を持ちますが、これはVARREYにおける要素の位置に対応する番号です。VARRAY内の要素数は、そのVARRAYのサイズを表します。VARRAY型を宣言する場合は、最大サイズを指定する必要があります。たとえば、次のようになります。

CREATE TYPE myNumType AS VARRAY(10) OF NUMBER;

この文では、10要素以下のNUMBER値を持つVARRAYが記述されたSQL型名として、myNumTypeが定義されています。

ネストした表は順序を設定していないデータ要素のセットで、すべて同じデータ型です。ネストした表はデータベースの別の表に格納されます。この表は単一の列を持ち、この列の型は組込み型またはオブジェクト型です。表がオブジェクト・タイプの場合、オブジェクト・タイプの各属性の列を持つ複数列の表として表示されることがあります。ネストした表は、次のようにして作成することができます。

CREATE TYPE myNumList AS TABLE OF integer;

この文は、INTEGER型のNESTED TABLEに使用される表タイプが定義されたSQL型名として、myNumListを指定しています。

マルチ・レベルのコレクション型の作成

JDBCにおいてマルチ・レベルのコレクション型を作成する最も一般的な方法は、java.sql.StatementクラスのexecuteメソッドにSQLのCREATE TYPE文を渡すことです。次のコードは、first_levelという1レベルのNESTED TABLEと、second_levelという2レベルのNESTED TABLEを作成します。

Connection conn = ....                            // make a database
// connection
Statement stmt = conn.createStatement();          // open a database
// cursor
stmt.execute("CREATE TYPE first_level AS TABLE OF NUMBER");  // create a nested
// table of number
stmt.execute("CREATE TYPE second_level AS TABLE OF first_level"); // create a
// two-levels nested table
...        // other operations here
stmt.close();                                     // release the
// resource
conn.close();                                     // close the
// database connection

マルチ・レベルのコレクション型を作成すると、実表の列またはオブジェクト型の属性として使用できます。

コレクション機能の概要

結果セットまたはコール可能文によって配列インスタンス内のコレクション・データを取得し、プリコンパイルされたSQL文またはコール可能文内のバインド変数として戻すことができます。

標準java.sql.Arrayインタフェースを実装するoracle.sql.ARRAYクラスは、Oracleコレクションのデータにアクセスし、更新するために必要な機能を提供します。

この項では、配列のgetterメソッドとsetterメソッドについて説明します。Java配列としてコレクションを取り出し、渡すには、次の結果セット、コール可能文およびプリコンパイルされたSQL文メソッドを使用します。

結果セットおよびコール可能文のgetterメソッド

OracleResultSetクラスとOracleCallableStatementクラスは、出力パラメータとして、つまりoracle.sql.ARRAYインスタンスまたはjava.sql.ArrayインスタンスとしてARRAYオブジェクトを取り出すために、getARRAY()メソッドとgetArray()メソッドをサポートします。getObjectメソッドも使用できます。これらのメソッドは、入力としてString列名またはint列索引を取ります。

プリコンパイルされたSQL文およびコール可能文のsetterメソッド

OraclePreparedStatementクラスとOracleCallableStatementクラスは、更新されたARRAYオブジェクトをバインド変数として取ってデータベースに渡すsetARRAYメソッドとsetArrayメソッドをサポートします。setObjectメソッドも使用できます。これらのメソッドは、oracle.sql.ARRAYインスタンスまたはjava.sql.Arrayインスタンスに加えて、Stringパラメータ名またはintパラメータ索引を入力として取ります。

ARRAYパフォーマンス拡張要素メソッド

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

- Javaプリミティブ型の配列としてのoracle.sql.ARRAY要素へのアクセス

- ARRAY自動要素バッファリング

- ARRAY自動索引作成

Javaプリミティブ型の配列としてのoracle.sql.ARRAY要素へのアクセス

oracle.sql.ARRAYクラスには、配列要素をJavaプリミティブ型として戻すメソッドが含まれています。これらのメソッドを使用すると、Datumインスタンスとしてコレクション要素にアクセスしてからDatumインスタンスをJavaプリミティブ型に変換する方法に比べ、より容易にコレクション要素にアクセスできます。

注意:
oracle.sql.ARRAYクラスのこれらの特殊なメソッドは、数値コレクションに制限されます。

最初のシグネチャを使用している各メソッドは、コレクション要素をXXX[]の形式で戻します。ここで、XXXはJavaプリミティブ型です。第2のシグネチャを使用している各メソッドは、countによって指定される数の要素を含んでいて、indexの場所で開始されるコレクションのスライスを戻します。

ARRAY自動要素バッファリング

Oracle JDBCドライバには、ARRAYの内容のバッファリングを有効または無効にするためのパブリック・メソッドが用意されています。

oracle.sql.ARRAYクラスには、次のメソッドがあります。

- setAutoBuffering

- getAutoBuffering

ARRAY要素にgetAttributesおよびgetArrayの各メソッドで複数回アクセスし、ARRAYデータがオーバーフローせずにJava仮想マシン(JVM)のメモリーに格納されると想定する場合は、JDBCアプリケーションで自動バッファリングを有効にすることをお薦めします。

重要:
変換した要素をバッファリングすると、JDBCアプリケーションでは、大量のメモリーが消費されます。

自動バッファリングを有効にすると、oracle.sql.ARRAYオブジェクトでは、変換したすべての要素のローカルのコピーが保持されます。このデータが保持されるため、この情報に2回目にアクセスするときにはデータ・フォーマット変換処理を実行しなくて済みます。

ARRAY自動索引作成

配列を自動索引作成モードにすると、配列オブジェクトは配列要素へのアクセスを迅速に行うために索引表をメンテナンスします。

oracle.sql.ARRAYクラスには、自動配列索引作成をサポートする次のメソッドが含まれています。

- setAutoIndexing

- setAutoIndexing

デフォルトでは、自動索引作成は有効にされていません。JDBCアプリケーションで、getArrayおよびgetResultSetの各メソッドを使用して配列要素のランダム・アクセスを実行する場合は、ARRAYオブジェクトの自動索引作成を有効にします。

配列の作成と使用方法

この項では、配列オブジェクトを作成する方法と、配列オブジェクトとしてコレクションを取り出し、渡す方法について説明します。内容は次のとおりです。

- ARRAYオブジェクトの作成

- 配列とその要素の取出し

- 配列の文オブジェクトへの引渡し

ARRAYオブジェクトの作成

注意:
Oracle JDBCでは、java.sql.ConnectionインタフェースのJDBC 4.0のcreateArrayOfメソッドはサポートされていません。Oracleの配列型はすべて名前付きですが、このメソッドでは匿名の配列型のみが許容されています。かわりにOracle固有のメソッド、oracle.jdbc.OracleConnection.createARRAYを使用してください。

この項では、ARRAYオブジェクトを作成する方法について説明します。この項の内容は次のとおりです。

- ARRAYオブジェクトの作成に関する手順

- マルチ・レベル・コレクションの作成

ARRAYオブジェクトの作成に関する手順

Oracle Database 11gリリース1(11.1)以降、oracle.jdbc.OracleConnectionインタフェースのcreateARRAYファクトリ・メソッドを使用して配列オブジェクトを作成することができます。配列を作成するファクトリ・メソッドは次のように定義されています。

public ARRAY createARRAY(java.lang.String typeName,java.lang.Object elements)throws SQLException

ここで、typeNameは、作成されたオブジェクトのSQL型の名前で、elementsは作成されたオブジェクトの要素です。

配列を作成するには次の操作を実行します。

1. CREATE TYPE文を使用して、次のようにコレクションを作成します。

CREATE TYPE elements AS varray(22) OF NUMBER(5,2);

elementsの内容は、次の2つの場合があります。

- Javaプリミティブ形の配列。たとえば、int[]です。

- xxx[]などのJavaオブジェクトの配列。ここで、xxxはJavaクラスの名前です。たとえば、Integer[]です。

2. 配列のユーザー定義SQL型名を指定しているJava文字列、および配列に含まれる個別の要素が含まれているJavaオブジェクトを渡すことによって、ARRAYオブジェクトを構築します。

ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);

マルチ・レベル・コレクションの作成

JDBCアプリケーションは、シングル・レベル・コレクションと同様、oracle.sql.ARRAYインスタンスを作成してマルチ・レベル・コレクションを表し、インスタンスをデータベースに送信することができます。シングル・レベル・コレクションを作成するために使用するのと同じcreateARRAYファクトリ・メソッドを使用することによってマルチ・レベル・コレクションを作成することもできます。シングル・レベル・コレクションを作成する場合、要素は一次元のJava配列ですが、マルチ・レベル・コレクションを作成する場合、要素はoracle.sql.ARRAY[]要素の配列、ネストJava配列、またはその組合せです。

次のコードは、ネストしたJava配列を使用してコレクション型を作成する方法を示します。

// prepare the multilevel collection elements as a nested Java array
int[][][] elements = { {{1}, {1, 2}}, {{2}, {2, 3}}, {{3}, {3, 4}} };

// create the ARRAY using the factory method
ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);

配列とその要素の取出し

この項では、結果セットからARRAYインスタンス全体を取り出す方法を最初に説明し、次にARRAYインスタンスから要素を取り出す方法について説明します。この項の内容は次のとおりです。

- 配列の取出し

- データ取出しメソッド

- データ取出しメソッドの比較

- 型マップに従った構造化オブジェクト配列の要素の取出し

- 配列要素のサブセットの取出し

- oracle.sql.Datum配列への配列要素の取出し

- マルチ・レベル・コレクション要素へのアクセス

配列の取出し

oracle.sql.ARRAYオブジェクトを戻すgetARRAYメソッドを使用して、結果セットをOracleResultSetオブジェクトにキャストすることで、SQL配列を結果セットから取り出すことができます。結果セットをキャストするのを避けるには、java.sql.ResultSetインタフェースによって指定された標準のgetObjectメソッドを使用してデータを取得し、その出力をoracle.sql.ARRAYにキャストします。

データ取出しメソッド

ARRAYオブジェクトを作成した後は、次に示すoracle.sql.ARRAYクラスの3つのオーバーロード・メソッドのいずれかを使用して、データを取り出すことができます。

- getArray

- getOracleArray

- getResultSet

Oracleは配列のすべての要素、またはサブセットを取り出すことができるメソッドも提供しています。

注意:
構造化オブジェクトの配列を操作している場合は、Oracleは、オブジェクトをJavaにマップする方法を選択できるように、型マップを指定できる次の3つのメソッドのバージョンを提供します。

getOracleArray

getOracleArray()メソッドは、標準Arrayインタフェースでは指定されていないOracle固有の拡張機能です。getOracleArrayメソッドでは、配列の要素値を取り出してDatum[]配列に格納します。この要素は、元の配列のSQL型データに対応するoracle.sql.*データ型です。

構造化オブジェクトの配列では、このメソッドは要素のためにoracle.sql.STRUCTインスタンスを使用します。

また、getOracleArray(index,count)メソッドを使用すると、配列要素のサブセットを取得できます。

getResultSet

getResultSetメソッドは、ARRAYオブジェクトによって示される配列の要素が含まれる結果セットを戻します。結果セットには、1つの配列要素ごとに1つの行があり、各行には2つの列があります。最初の列には、配列内でその要素を参照する索引が格納され、2つめの列には要素値が格納されます。VARRAYの場合、索引は配列内での要素の位置を表します。定義上、順序付けられていないネスト表の場合、索引は特定の問合せにおける要素の戻り順のみを反映します。

NESTED TABLEからデータを取り出すときは、getResultSetを使用することをお薦めします。NESTED TABLEの要素数には、制限はありません。メソッドから戻されたResultSetオブジェクトのポインタの初期値は、データの第1行です。nextメソッドおよび適切なgetXXXメソッドを使用すると、NESTED TABLEの内容を取得できます。また、getArrayを使用すると、NESTED TABLEのすべての内容が一度に戻されます。

getResultSetメソッドでは、接続のデフォルト型マップを使用して、OracleオブジェクトのSQL型とその対応するJavaデータ型間のマッピングを決定します。接続のデフォルト型マップを使用しない場合は、getResultSet(map)を使用して別の型マップを指定できます。

また、getResultSet(index,count)およびgetResultSet(index,count,map)メソッドを使用すると、配列のサブセットを取り出すことができます。

getArray

getArrayメソッドは、必要に応じてキャストできるjava.lang.Objectとして配列要素を戻す標準JDBCメソッドです。要素は、元の配列のSQL型データに対応するJava型データに変換されます。

また、getArray(index,count)メソッドを使用すると、配列要素のサブセットを取り出すことができます。

データ取出しメソッドの比較

配列要素を戻すためにgetOracleArrayを使用する場合は、そのメソッドがoracle.sql.Datumインスタンスを使用するため、SQLからJavaへのデータ変換を行う必要がなくなります。Datumクラスまたはそのサブクラスのインスタンス内にある文字以外のデータは、RAW SQL形式で保持されます。

getResultSetを使用してプリミティブ・データ型の配列を戻す場合、JDBCドライバはResultSetオブジェクトを戻します。このオブジェクトには、各要素ごとに、その要素を配列内で参照する索引と要素値が含まれます。たとえば、次のようになります。

ResultSet rset = intArray.getResultSet();

この場合、結果セットには、1つの配列要素ごとに1つの行があり、各行には2つの列があります。最初の列には、配列内でその要素を参照する索引が格納され、2つめの列には要素値が格納されます。

配列の要素が、Java型にマップするSQL型の場合、getArrayはこのJava型の要素の配列を戻します。getArrayメソッドの戻り型はjava.lang.Objectです。したがって、結果は使用する前にキャストする必要があります。

BigDecimal[] values = (BigDecimal[]) intArray.getArray();

ここで、intArrayはoracle.sql.ARRAYで、NUMBER型のVARRAYに対応しています。values配列にはjava.math.BigDecimal型の要素の配列が含まれます。これはSQL NUMBERデータ型が、デフォルトで、Oracle JDBCドライバによって、Java BigDecimalにマップされるためです。

注意:
BigDecimalの使用は、リソースを大量に消費するJavaの操作です。Oracle JDBCは数値SQLデータをデフォルトでBigDecimalにマップするため、getArrayを使用するとパフォーマンスに影響を与える可能性があり、数値のコレクションの場合は推奨されません。

型マップに従った構造化オブジェクト配列の要素の取出し

デフォルトでは、構造化オブジェクトの要素を持つ配列を操作しているときに、getArrayまたはgetResultSetを使用すると、デフォルト・マッピングに従って配列のOracleオブジェクトが、対応するJavaデータ型にマップされます。これは、これらのメソッドでは、接続のデフォルト型マップを使用してマッピングが決定されるためです。

ただし、デフォルトの処理を変更する場合は、getArray(map)またはgetResultSet(map)メソッドを使用して、別のマッピングを含む型マップを指定できます。配列のOracleオブジェクトに対応するエントリが型マップに存在する場合は、配列の各オブジェクトは、その型マップで指定されている、対応するJava型にマップされます。たとえば、次のようになります。

Object[] object = (Object[])objArray.getArray(map);

この例のobjArrayはoracle.sql.ARRAYオブジェクトを表し、mapはjava.util.Mapオブジェクトを表します。

型マップに特定のOracleオブジェクトに対応するエントリが含まれない場合は、要素はoracle.sql.STRUCTオブジェクトとして戻されます。

getResultSet(map)メソッドは、getArray(map)メソッドと同じように動作します。

関連項目:
「型マップを使用した配列要素のマップ」

配列要素のサブセットの取出し

配列の内容全体を取り出さない場合は、サブセットを取り出すことができるgetArray、getResultSetおよびgetOracleArrayのシグネチャを使用できます。配列のサブセットを取り出すには、索引と件数を渡して、取出しを開始する配列の位置および取り出す要素数を指定します。前の例と同様に、接続に対して型マップを指定するか、またはデフォルトの型マップを使用して、Java型に変換します。たとえば、次のようになります。

Object object = arr.getArray(index, count, map);
Object object = arr.getArray(index, count);

getResultSetを使用した例です。

ResultSet rset = arr.getResultSet(index, count, map);
ResultSet rset = arr.getResultSet(index, count);

getOracleArrayを使用した例です。

Datum[] arr = arr.getOracleArray(index, count);

arrはoracle.sql.ARRAYオブジェクト、indexはlong型、countはint型、mapはjava.util.Mapオブジェクトを表します。

注意:
配列全体ではなく、配列のサブセットを取り出すことにパフォーマンス上の利点はありません。

oracle.sql.Datum配列への配列要素の取出し

oracle.sql.Datum[]配列を戻すには、getOracleArrayを使用します。戻される配列の要素は、元の配列要素のSQLデータ型に対応するoracle.sql.*型です。たとえば、次のようになります。

Datum arraydata[] = arr.getOracleArray();

arrはoracle.sql.ARRAYオブジェクトを表します。

次の例は、接続オブジェクトconnおよび文オブジェクトstmtがすでに作成済であることを前提としています。この例では、SQL型名NUM_ARRAYの配列がNUMBERデータのVARRAYを格納するために作成されます。NUM_ARRAYは、表VARRAY_TABLEに格納されます。

問合せは、VARRAY_TABLEの内容を選択します。結果セットはOracleResultSetにキャストされます。それに対してgetARRAYが適用され、配列データがmy_arrayに取得されます。これはoracle.sql.ARRAYオブジェクトです。

my_arrayはoracle.sql.ARRAY型の配列であるため、getSQLTypeNameメソッドおよびgetBaseTypeメソッドをこの配列に適用すれば、その配列の要素ごとに、その整数コードでSQL型名を戻すことができます。

次に、プログラムにより配列の内容が出力されます。NUM_ARRAYの内容はSQLデータ型NUMBERであるため、my_arrayの要素はBigDecimal型です。要素を使用するには、最初に、その要素をBigDecimalにキャストする必要があります。forループでは、配列の各値はBigDecimalにキャストされ、標準出力に出力されます。

stmt.execute ("CREATE TYPE num_varray AS VARRAY(10) OF NUMBER(12, 2)");
stmt.execute ("CREATE TABLE varray_table (col1 num_varray)");
stmt.execute ("INSERT INTO varray_table VALUES (num_varray(100, 200))");

ResultSet rs = stmt.executeQuery("SELECT * FROM varray_table");
ARRAY my_array = ((OracleResultSet)rs).getARRAY(1);

// return the SQL type names, integer codes,
// and lengths of the columns
System.out.println ("Array is of type " + array.getSQLTypeName());
System.out.println ("Array element is of type code " + array.getBaseType());
System.out.println ("Array is of length " + array.length());

// get Array elements
BigDecimal[] values = (BigDecimal[]) my_array.getArray();

for (int i=0; i<values.length; i++)
{
BigDecimal out_value = (BigDecimal) values[i];
System.out.println(">> index " + i + " = " + out_value.intValue());
}

getResultSetを使用して配列を取得する場合は、最初に結果セット・オブジェクトを取得し、次にnextメソッドを使用して操作を反復する必要があるので、注意が必要です。getIntメソッドでは、パラメータの索引を使用して、要素の索引および要素値を取り出します。

ResultSet rset = my_array.getResultSet();
while (rset.next())
{
// The first column contains the element index and the
// second column contains the element value
System.out.println(">> index " + rset.getInt(1)+" = " + rset.getInt(2));
}

マルチ・レベル・コレクション要素へのアクセス

oracle.sql.ARRAYクラスは、コレクション要素にアクセスするために、オーバーロードされた3つのメソッドを提供します。JDBCドライバは、これらのメソッドをマルチ・レベル・コレクションをサポートするように拡張します。メソッドは次のとおりです。

- getArrayメソッド

- getOracleArrayメソッド

- getResultSetメソッド

getArrayメソッドは、コレクション要素を保持するJava配列を戻します。配列要素の型は、コレクション要素の型とJDBCのデフォルトの変換マトリックスによって決まります。

たとえば、getArrayメソッドは、SQL NUMBER型のコレクションのjava.math.BigDecimal配列を戻します。getOracleArrayメソッドは、Datum形式でコレクション要素を保持するDatum配列を戻します。マルチ・レベル・コレクションの場合、getArrayメソッドおよびgetOracleArrayメソッドはいずれも、oracle.sql.ARRAY要素のJava配列を戻します。

getResultSetメソッドは、マルチ・レベル・コレクション要素をラップするResultSetオブジェクトを戻します。マルチ・レベル・コレクションの場合、JDBCアプリケーションはResultSetクラスのgetObject、getARRAYまたはgetArrayメソッドを使用して、oracle.sql.ARRAYのインスタンスとしてコレクション要素にアクセスします。

次のコードは、getOracleArray、getArrayおよびgetResultSetメソッドの使用方法を示します。

Connection conn = ...;          // make a JDBC connection
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery ("select col2 from tab2 where idx=1");

while (rset.next())
{
ARRAY varray3 = (ARRAY) rset.getObject (1);
Object varrayElems = varray3.getArray (1);
// access array elements of "varray3"
Datum[] varray3Elems = (Datum[]) varrayElems;

for (int i=0; i<varray3Elems.length; i++)
{
ARRAY varray2 = (ARRAY) varray3Elems[i];
Datum[] varray2Elems = varray2.getOracleArray();
// access array elements of  "varray2"

for (int j=0; j<varray2Elems.length; j++)
{
ARRAY varray1 = (ARRAY) varray2Elems[j];
ResultSet varray1Elems = varray1.getResultSet();
// access array elements   of "varray1"

while (varray1Elems.next())
System.out.println ("idx="+varray1Elems.getInt(1)+"
value="+varray1Elems.getInt(2));
}
}
}
rset.close ();
stmt.close ();
conn.close ();

配列の文オブジェクトへの引渡し

この項では、プリコンパイルされたSQL文オブジェクトまたはコール可能文オブジェクトに配列を渡す方法について説明します。

配列のプリコンパイルされたSQL文への引渡し

次の手順に従って、配列をプリコンパイルされたSQL文に渡します。

注意:
配列は、INまたはOUTバインド変数として使用できます。

1. プリコンパイルされたSQL文にoracle.sql.ARRAYオブジェクトとして渡す配列を定義します。

ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);

sql_type_nameは配列のユーザー定義SQL型名を指定するJava文字列を表し、elementsは要素のJava配列を含むjava.lang.Objectを表します。

2. 実行するSQL文を含むjava.sql.PreparedStatementオブジェクトを作成します。

3. プリコンパイルされたSQL文をOraclePreparedStatementにキャストし、setARRAY()を使用して、プリコンパイルされたSQL文に配列を渡します。

(OraclePreparedStatement)stmt.setARRAY(parameterIndex, array);

parameterIndexはパラメータ索引を表し、arrayは手順2で作成したoracle.sql.ARRAYオブジェクトを表します。

4. プリコンパイルされたSQL文を実行します。

配列のコール可能文への引渡し

コレクションをPL/SQLブロックのOUTパラメータとして取り出すには、次の手順を実行してOUTパラメータのバインド型を登録します。

1. 次のように、コール可能文をOracleCallableStatementにキャストします。

OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{? = call func()}");

2. 次の形式のregisterOutParameterメソッドを使用して、OUTパラメータを登録します。

ocs.registerOutParameter
(int param_index, int sql_type, string sql_type_name);

param_indexはパラメータ索引、sql_typeはSQL型コード、sql_type_nameは配列型の名前です。この場合、sql_typeはOracleTypes.ARRAYです。

3. 次のように、コールを実行します。

ocs.execute();

4. 次のように、値を取得します。

oracle.sql.ARRAY array = ocs.getARRAY(1);

型マップを使用した配列要素のマップ

配列にOracleオブジェクトが含まれる場合は、型マップを使用して、配列のオブジェクトを、対応するJavaクラスに関連付けることができます。型マップを指定しない場合または型マップに特定のOracleオブジェクトのエントリが含まれない場合は、oracle.sql.STRUCTオブジェクトとして各要素が戻されます。

型マップを使用して、配列のOracleオブジェクトと対応するJavaクラスとのマッピングを決定するときは、マップに適切なエントリを追加する必要があります。

次の例では、型マップを使用して配列要素をカスタムJavaオブジェクト・クラスにマップする方法を説明します。この例の配列は、NESTED TABLEです。この例では、まず、名前属性と従業員番号属性が設定されているEMPLOYEEオブジェクトを定義します。EMPLOYEE_LISTはEMPLOYEEオブジェクトのNESTED TABLE型です。次に、会社内の部署名および各部署の従業員名を格納するEMPLOYEE_TABLEを作成します。EMPLOYEE_TABLEの中では、従業員はEMPLOYEE_LIST表の形式で格納されます。

stmt.execute("CREATE TYPE EMPLOYEE AS OBJECT
(EmpName VARCHAR2(50),EmpNo INTEGER))");

stmt.execute("CREATE TYPE EMPLOYEE_LIST AS TABLE OF EMPLOYEE");

stmt.execute("CREATE TABLE EMPLOYEE_TABLE (DeptName VARCHAR2(20),
Employees EMPLOYEE_LIST) NESTED TABLE Employees STORE AS ntable1");

stmt.execute("INSERT INTO EMPLOYEE_TABLE VALUES ("SALES", EMPLOYEE_LIST
(EMPLOYEE('Susan Smith', 123), EMPLOYEE('Scott Tiger', 124)))");

SALES部門に属するすべての従業員をカスタム・オブジェクト・クラスEmployeeObjのインスタンスの配列に取り込む場合は、EMPLOYEE SQL型とEmployeeObjカスタム・オブジェクト・クラス間のマッピングを指定するために、型マップにエントリを追加する必要があります。

これを実行するには、まず文と結果セット・オブジェクトを作成し、次に、SALES部門に関連付けられているEMPLOYEE_LISTを結果セットに選択します。getARRAYメソッドを使用してEMPLOYEE_LISTをARRAYオブジェクト(次の例ではemployeeArray)に取得できるように、結果セットをOracleResultSetにキャストします。

この例のEmployeeObjカスタム・オブジェクト・クラスは、SQLDataインタフェースを実装しています。

Statement s = conn.createStatement();
OracleResultSet rs = (OracleResultSet)s.executeQuery
("SELECT Employees FROM employee_table WHERE DeptName = 'SALES'");

// get the array object
ARRAY employeeArray = ((OracleResultSet)rs).getARRAY(1);

EMPLOYEE_LISTオブジェクトを取り出したので、既存の型マップを取得し、SQL型EMPLOYEEをJava型EmployeeObjにマップするエントリを追加します。

// add type map entry to map SQL type
// "EMPLOYEE" to Java type "EmployeeObj"
Map map = conn.getTypeMap();
map.put("EMPLOYEE", Class.forName("EmployeeObj"));

次に、EMPLOYEE_LISTからSQL EMPLOYEEオブジェクトを取り出します。この操作をするには、employeeArray配列オブジェクトのgetArrayメソッドをコールします。このメソッドにより、オブジェクト配列が戻されます。getArrayメソッドでは、employeesオブジェクト配列にEMPLOYEEオブジェクトが戻されます。

// Retrieve array elements
Object[] employees = (Object[]) employeeArray.getArray();

最後にループを作成して、各EMPLOYEE SQLオブジェクトに、EmployeeObj Javaオブジェクトのempを割り当てます。

// Each array element is mapped to EmployeeObj object.
for (int i=0; i<employees.length; i++)
{
EmployeeObj emp = (EmployeeObj) employees[i];
...
}

JPublisherで生成するカスタム・コレクション・クラス

この項では、主にoracle.sql.ARRAYクラスの機能について説明しています。ただし、カスタムJavaクラス、より厳密にはカスタム・コレクション・クラスからも、Oracleコレクションにアクセスできます。

カスタム・コレクション・クラスは自分で作成できますが、Oracle JPublisherユーティリティを使用するのが最も便利な方法です。JPublisherによって生成されるカスタム・コレクション・クラスには、この章で前述したすべての機能に加えて、次の利点があります。

- カスタム・コレクション・クラスは、強い型指定です。この強い型指定により、実行時まで検出できないコーディング・エラーを、コンパイル時に発見できます。

- カスタム・コレクション・クラスは変更できます(可変)。JPublisherによって作成されるカスタム・コレクション・クラスでは、ARRAYクラスとは異なり、getElementメソッドとsetElementメソッドを使用して個々の要素を取得および設定できます。

カスタム・コレクション・クラスは、次の3つの要件を満たす必要があります。

- oracle.sql.ORADataインタフェースを実装する必要があります。カスタム・オブジェクト・クラスにかわる標準JDBC SQLDataインタフェースは、カスタム・コレクション・クラス用ではないことに注意してください。

- このクラスまたはコンパニオン・クラスで、カスタム・コレクション・クラスのインスタンスを作成するには、oracle.sql.ORADataFactoryインタフェースを実装する必要があります。

- コレクション・データを格納する手段が必要です。一般に、この目的のためにoracle.sql.ARRAY属性が直接または間接的に挿入されます。

JPublisherによって作成されるカスタム・コレクション・クラスは、ORADataとORADataFactoryを実装し、oracle.sql.ARRAY属性を間接的に挿入します。生成されたカスタム・コレクション・クラスは、oracle.jpub.runtime.MutableArray属性を持ちます。MutableArrayクラスは、oracle.sql.ARRAY属性を持ちます。

注意:
JPublisherを使用してカスタム・コレクション・クラスを作成する場合は、ORAData実装を使用する必要があります。これは、JPublisher -usertypesマッピング・オプションが、デフォルトのoracleに設定されている場合に当てはまります。
カスタム・コレクション・クラスではSQLData実装を使用できません。-usertypesマッピング・オプションをjdbcに設定することは無効です。

強い型指定のカスタム・コレクション・クラスの例として、OracleコレクションMYVARRAYを定義する場合は、JPublisherはMyVarrayカスタム・コレクション・クラスを作成できます。汎用oracle.sql.ARRAYインスタンスのかわりにMyVarrayインスタンスを使用すると、実行時ではなくコンパイル時のエラーを簡単に捕捉できます。たとえば、MyVarray変数に別の種類の配列を間違えて割り当てた場合は、簡単にエラーが検出されます。

カスタム・コレクション・クラスを使用しない場合は、コレクションをマップするために標準java.sql.Arrayインスタンス、またはoracle.sql.ARRAYインスタンスを使用します。

関連項目:

- 「JPublisherを使用したカスタム・オブジェクト・クラスの作成」

- 『Oracle Database JPublisherユーザーズ・ガイド』

17 結果セット

Java Development Kit(JDK)の標準Java Database Connectivity(JDBC)機能には、結果セット機能の拡張が含まれています。拡張には、前方または後方への処理、相対的または絶対的な位置指定、内部または外部で生じたデータベースに対する変更の参照、および結果セット・データの更新と更新による変更内容のデータベースへのコピーがあります。

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

- 結果セットのサポートのOracle JDBC実装概要

- 結果セットの制限事項およびダウングレード・ルール

- 更新の競合回避

- フェッチ・サイズ

- 行の再フェッチ

- 内部的および外部的に加えられたデータベース変更の参照

結果セットのサポートのOracle JDBC実装概要

この項では、スクロール可能性(クライアント側キャッシュを使用)および更新可能性(ROWIDを使用)を実現する結果セットのサポートのOracle JDBC実装に関する主要な視点について説明します。

ユーザーは、独自のクライアント側キャッシュ・メカニズムを実装できます。そのためのインタフェースが提供されています。

結果セットのスクロール可能性のOracle JDBC実装

基礎となるサーバーでスクロール可能なカーソルがサポートされないため、Oracle JDBCが、別々のレイヤーでスクロール可能性を実装する必要があります。

この機能は、スクロール可能な結果セットの行をクライアント側のメモリー・キャッシュに格納することにより、実現されていることに注意してください。

重要:
あらゆるスクロール可能な結果セットのすべての行がクライアント側キャッシュに格納されるため、結果セットに多くの行、多くの列または非常に大きな列が含まれる場合、クライアント側Java仮想マシン(JVM)に障害が発生する原因になる可能性があります。大きな結果セットに対してはスクロール可能性を指定しないでください。

結果セットの更新可能性のOracle JDBC実装

更新可能性をサポートするために、Oracle JDBCはROWIDを使用して、結果セットに出現するデータベース行を一意に識別します。更新可能な結果セットに問い合せるたびに、選択された列とともに、Oracle JDBCドライバによって自動的にROWIDが取り出されます。

注意:
更新可能性そのものは、クライアント側のキャッシュを必要としません。特に、forward-only更新可能結果セットは、クライアント側のキャッシュを必要としません。

結果セットの制限事項およびダウングレード・ルール

一部の結果セット型は、ある種類の問合せには不適切です。実行する問合せに対して不適切な結果セット型または同時実行性型が指定されている場合、JDBCドライバは次のルール・セットに従い、かわりに使用する最適な型を判断します。

指定された結果セット型または同時実行性型が不適切な場合、実際の結果セット型と同時実行性型は、文が実行されるときに、文オブジェクト上で SQLWarning を発行しているドライバを使用して決定されます。SQLWarning オブジェクトには、要求した型が不適切だった理由が含まれます。要求した結果セットの型を受け取ったかどうか確認するには、警告を確認してください。

結果セットの制限事項

拡張された結果セットの問合せには、次の制限事項が適用されます。次の指針に当てはまらない場合、JDBCドライバによって、代替の結果セット型または同時実行性型が選択されます。

更新可能な結果セットを作成するには、次の制限事項を考慮します。

- 問合せによって選択できるのは、単一の表のみです。結合操作を含めることはできません。
さらに、挿入するためには、NULL化可能でない列およびデフォルト値が設定されていない列をすべて、問合せによって選択する必要があります。

- 問合せではSELECT *を使用できません。
ただし、回避方法があります。

- 問合せで選択できるのは、表列のみです。
導出列や、列の集合のSUMまたはMAXなど、集合体を選択できません。

scroll-sensitive結果セットを作成するには、次の制限事項を考慮します。

- 問合せではSELECT *を使用できません。
ただし、回避方法があります。

- 問合せによって選択できるのは、単一の表のみです。

スクロール可能結果セットおよび更新可能結果セットでは、Streamなどの列を使用できません。サーバーでStream列をフェッチする必要がある場合は、フェッチ・サイズを1に減らし、Stream列の読込みが終了するまで、Stream列に続くすべての列をブロックします。このため、列を一括でフェッチし、スクロールすることはできません。

回避方法

SELECT *の制限事項を回避するには、次の例のように、表の別名を使用します。

SELECT t.* FROM TABLE t ...

注意:
ある問合せから、scroll-sensitiveまたは更新可能な結果セットを作成できるかどうかを判断する簡単な方法があります。ROWID列を問合せリストに追加できる場合は、その問合せからscroll-sensitiveまたは更新可能な結果セットを作成できます。

結果セットのダウングレード・ルール

指定された結果セット型または同時実行性型が不適切な場合、Oracle JDBCドライバは次のルールを使用して、代替型を選択します。

- 指定した結果セット型がTYPE_SCROLL_SENSITIVEであるにもかかわらず、JDBCドライバがその要求を完全には満たせない場合、JDBCドライバはTYPE_SCROLL_INSENSITIVEにダウングレードしようとします。

- 指定した結果セット型またはダウングレード後の結果セット型がTYPE_SCROLL_INSENSITIVEであるにもかかわらず、JDBCドライバがその要求を完全には満たせない場合、JDBCドライバはTYPE_FORWARD_ONLYにダウングレードしようとします。

- 指定した同時実行性型がCONCUR_UPDATABLEであるにもかかわらず、JDBCドライバがその要求を完全には満たせない場合、JDBCドライバはCONCUR_READ_ONLYにダウングレードしようとします。

注意:
JDBCドライバによる結果セット型および同時実行性型の操作は、それぞれ独立しています。

結果セット型および同時実行性型の検証

問合せを実行した後、結果セット・オブジェクトのメソッドをコールすることにより、JDBCドライバが実際に使用した結果セット型と同時実行性型を検証できます。

- int getType() throws SQLException
このメソッドは、問合せに対して使用された結果セット型のint値を戻します。ResultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_SENSITIVEまたはResultSet.TYPE_SCROLL_INSENSITIVEという値が戻されます。

- int getConcurrency() throws SQLException
このメソッドは、問合せに対して使用された同時実行性型のint値を戻します。ResultSet.CONCUR_READ_ONLYまたはResultSet.CONCUR_UPDATABLEという値が戻されます。

更新の競合回避

JDBCドライバで使用される更新可能な結果セットに関しては、次の事項に注意してください。

- ドライバは、更新可能な結果セットに対する書込みロックを施行しません。

- ドライバは、結果セットのDELETEまたはUPDATE操作の競合をチェックしません。

DELETEまたはUPDATE操作を、コミットされた別のトランザクションによって更新された行に対して実行すると、競合が発生します。

Oracle JDBCドライバは、ROWIDを使用し、データベース表の行を一意に識別します。ドライバがUPDATEまたはDELETE操作をデータベースに送信しようとしたとき、ROWIDが有効であれば、操作は実行されます。

コミットされた別のトランザクションによる変更は、レポートされません。競合は警告なしに無視され、新しい変更によって前の変更は上書きされます。

競合を回避するには、結果セットを作成する問合せを実行するときに、OracleのFOR UPDATE機能を使用します。これにより、競合を回避できますが、データへの同時アクセスも禁止されます。データ項目に同時に設定できる書込みロックは1つのみです。

フェッチ・サイズ

デフォルトでは、Oracle JDBCは問合せを実行するとき、データベース・カーソルから一度に10行の結果セットを受け取ります。これが、デフォルトのOracle行フェッチ・サイズ値です。データベース・カーソルへの1回のラウンドトリップで取り出される行の数を変更するには、行フェッチ・サイズ値を変更します。

標準JDBCでは、1つの問合せの1回のデータベース・ラウンドトリップでフェッチされる行の数を指定することもできます。この数はフェッチ・サイズと呼ばれます。Oracle JDBCでは、行プリフェッチ値が、文オブジェクトのデフォルト・フェッチ・サイズとして使用されます。フェッチ・サイズを設定すると、行プリフェッチ設定より優先され、その文オブジェクトを介して実行される後続の問合せに適用されます。

フェッチ・サイズは、結果セットでも使用されます。文オブジェクトが問合せを実行するとき、文オブジェクトのフェッチ・サイズが、その問合せで作成される結果セット・オブジェクトに渡されます。ただし、結果セット・オブジェクトでフェッチ・サイズを設定して、渡された文フェッチ・サイズをオーバーライドすることもできます。

注意:
結果セットが作成された後で文オブジェクトのフェッチ・サイズを変更しても、結果セットには影響を与えません。

明示的に設定された場合でも、渡された文フェッチ・サイズと等しいデフォルトでも、結果セット・フェッチ・サイズによって、その結果セットでの後続のデータベースへのラウンドトリップで取り出される行の数が判断されます。このラウンドトリップには、元の問合せを完了するために必要なラウンドトリップと、結果セットへのデータの再フェッチに必要なラウンドトリップが含まれます。scroll-sensitiveまたはscroll-insensitive/更新可能な結果セットを更新するために、データは明示的または暗黙的に再フェッチされる可能性があります。

フェッチ・サイズの設定

Statement、PreparedStatement、CallableStatementおよびResultSetオブジェクトのすべてで、フェッチ・サイズを設定および取り出す次のメソッドが使用可能です。

- void setFetchSize(int rows) throws SQLException

- int getFetchSize() throws SQLException

問合せのフェッチ・サイズを設定するには、問合せを実行する前に文オブジェクトのsetFetchSizeをコールします。フェッチ・サイズをNに設定すると、1回のデータベースへのラウンドトリップで、N行がフェッチされます。

問合せを実行した後、結果セット・オブジェクト上でsetFetchSizeをコールすることで、渡された文オブジェクト・フェッチ・サイズをオーバーライドすることができます。これは、元の問合せに応じてさらに行を取得するための後続のアクセスすべてと、それ以降の、行の再フェッチすべてに適用されます。

フェッチ方向のプリセット

標準JDBCでは、結果セットの処理に使用するために、フェッチ方向と呼ばれる方向を事前に指定できます。これにより、JDBCドライバの処理を最適化できます。次の結果セット・メソッドが指定されます。

- void setFetchDirection(int direction) throws SQLException

- int getFetchDirection() throws SQLException

Oracle JDBCドライバは前方へのプリセット値のみをサポートします。これは、ResultSet.FETCH_FORWARD静的定数値を入力することにより、指定できます。

ResultSet.FETCH_REVERSEおよびResultSet.FETCH_UNKNOWNという値はサポートされていません。指定しようとすると、SQL警告が発生し、設定は無視されます。

行の再フェッチ

結果セットのrefreshRow メソッドは、一部の種類の結果セットで、データを再フェッチするためにサポートされています。具体的には、データベースに戻って、結果セットの現在の行からのn行に対応するデータベース行を再取得します。ここで、nはフェッチ・サイズです。これを使用すると、周囲のトランザクションの分離レベルに応じて、結果セットの外部で行われたデータベースの最新の更新を参照できます。

再フェッチすると、すでに結果セットにある行に対応する行のみを再取得します。元の問合せ以降にデータベースで挿入や削除が行われた行については何もしません。挿入された行は無視されます。また、対応する行がデータベースから削除された後も、結果セットの行はそのまま残ります。データベースで削除された行を再フェッチしようとした場合、それに対応する結果セットの行は、元の値を維持します。

注意:
いくつかの基準を持つ問合せに基づいてTYPE_SCROLL_SENSITIVE結果セットを宣言してから、列の値が問合せの基準に一致しなくなるように外部的に行を更新すると、ドライバは、行がデータベースから削除され、送信された問合せでは取り出せないかのように動作します。このため、refreshRowメソッドをコールしても個別行の更新は確認できません。

refreshRowメソッドのシグネチャを示します。

void refreshRow() throws SQLException

このメソッドをコールするときは、行境界の外側や挿入行ではなく、有効な現在行に位置指定しておく必要があります。

次の結果セットのカテゴリで、refreshRowメソッドがサポートされています。

- scroll-sensitive/読取り専用

- scroll-sensitive/更新可能

- scroll-insensitive/更新可能

注意:
Scroll-Sensitive結果セット機能は、refreshRowの暗黙的なコールによって実装されます。

内部的および外部的に加えられたデータベース変更の参照

この項では、次の事項を参照する結果セットの機能について説明します。

- 内部変更と呼ばれる結果セット自体の変更

- 外部変更と呼ばれる、結果セット以外から加えられた変更(ユーザー自身による結果セット外のトランザクションによる変更、またはその他のコミットされたトランザクションによる変更)

注意:
Sun社の標準JDBCの仕様では、外部変更は「他からの変更」と呼ばれています。

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

- 外部変更の可視性と検出

- 内部変更および外部変更の可視性の概要

- Scroll-Sensitive結果セットのOracle実装

外部変更の可視性と検出

外部ソースによって基礎となるデータベースに加えられる変更に関して、2つの概念があります。これらは似ていますが、ローカルな結果セットからの変更の可視性という観点から見ると異なります。

- 変更の可視性

- 変更の検出

「可視である」変更とは、結果セットの行を見たとき、外部ソースによってデータベースの対応する行に加えられた変更からの新しいデータ値を参照できるという意味です。

一方、「検出される」変更とは、結果セットに最初に値が移入されて以降の新しい値であることを、結果セットが認識するという意味です。

Oracle結果セットでは、新しいデータを参照したときでも(scroll-sensitive結果セットでの外部UPDATEのように)、このデータが結果セットへの移入後に変更されたことは認識されません。このような変更は、検出されません。

内部変更および外部変更の可視性の概要

表17-1では、Oracle JDBC実装の結果セット・オブジェクトが、結果セット自体が内部的に実行した変更および基礎となるデータベースに対してユーザー自身のトランザクション、またはその他のコミットされたトランザクションから外部的に実行された変更を参照できるかどうかについての状況を要約します。

表17-1 Oracle JDBCでの内部変更および外部変更の可視性

結果セット型

内部的なDELETEの参照が可能か

内部的なUPDATEの参照が可能か

内部的なINSERTの参照が可能か

外部的なDELETEの参照が可能か

外部的なUPDATEの参照が可能か

外部的なINSERTの参照が可能か

forward-only

不可

可

不可

不可

不可

不可

scroll-sensitive

可

可

不可

不可

可

不可

scroll-insensitive

可

可

不可

不可

不可

不可

注意:

- refreshRowメソッドの明示的な使用は、外部変更の可視性の概念とは別です。

- scroll-sensitive結果セットを基礎とするUPDATE操作のように、外部変更が可視であるときでも、これらは検出されません。結果セットのrowDeleted、rowUpdatedおよびrowInsertedメソッドは常にfalseを戻します。

Scroll-Sensitive結果セットのOracle実装

scroll-sensitive結果セットのOracle実装にはウィンドウの概念があり、フェッチ・サイズに基づくウィンドウ・サイズを持ちます。ウィンドウ・サイズは、結果セット内で行が更新される頻度に影響を及ぼします。

指定された行へ移動することによって現在の行を確定した場合、ウィンドウは結果セットのその行から始まるn行です。ここで、nは、結果セットによって使用されているフェッチ・サイズです。結果セットが先に作成された場合、現在の行がなく、したがってウィンドウもない点に注意してください。デフォルトの位置は最初の行の前です。これは有効な現在の行ではありません。

行を移動するとき、現在行がウィンドウ内にある間は、ウィンドウは変更されません。しかし、ウィンドウの外にある新しい現在行に移動すると、新しい現在行から始まるN行のウィンドウが再定義されます。

ウィンドウが再定義されると、refreshRowメソッドが暗黙的にコールされ、新しいウィンドウの行に対応するデータベースのN行が自動的に再フェッチされます。これにより、新しいウィンドウのデータが更新されます。

そのため、外部更新は、scroll-sensitive結果セットですぐには参照できません。前述のように、自動再フェッチの後で参照できるようになります。

注意:
この種の再フェッチは、高度に効率的または最適化されている方法論ではないので、パフォーマンスについては、無視できない不安があります。現在実装されているようなscroll-sensitive結果セットを使用する場合は、あらかじめ慎重に検討してください。sensitivityとパフォーマンスの間にも重大なトレードオフがあります。最もsensitiveな結果セットはフェッチ・サイズが1であるものです。この場合、行を移動するたびに新しい現在の行が再フェッチされます。ただし、これはアプリケーションのパフォーマンスに重大な影響を及ぼします。

18 JDBC RowSet

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

- JDBC RowSetの概要

- CachedRowSet

- JdbcRowSet

- WebRowSet

- FilteredRowSet

- JoinRowSet

JDBC RowSetの概要

RowSetは、Java Database Connectivity(JDBC)の結果セットまたは表形式データソースの一連の行をカプセル化するオブジェクトです。RowSetは、JavaBeansなどのコンポーネント・ベースの開発モデル、一連の標準プロパティおよびイベント通知メカニズムをサポートしています。

RowSetsは、JDBC 2.0で、オプションのパッケージによって導入されました。ただし、RowSetsの実装はJDBC RowSet Implementations Specification(JSR-114)で標準化され、Java Platform, Standard Edition(Java SE)5.0以降、オプションでないパッケージとして利用できます。Java SE 6.0 RowSetsには、RowIdや各国語キャラクタ・セットなどのような機能をサポートするAPIがより多く含まれます。Java SE Javadocには、JDBC RowSetの実装のための、標準インタフェースと基本クラスに関する情報が含まれています。

関連項目:

- JSR-114仕様: http://jcp.org/en/jsr/detail?id=114

- Java SE 5.0のJavadoc: http://download.oracle.com/javase/1.5.0/docs/api/

- Java SE 6.0のJavadoc: http://download.oracle.com/javase/6/docs/api/

注意:
内容に矛盾がある場合は、JSR-114仕様がJDK 5.0のJavadocより優先されます。

JSR-114仕様には、次の5種類のRowSetの実装詳細が記載されています。

- CachedRowSet

- JdbcRowSet

- WebRowSet

- FilteredRowSet

- JoinRowSet

Oracle JDBCは、5種類のRowSetすべてを、oracle.jdbc.rowsetパッケージにあるインタフェースおよびクラスを介してサポートしています。Oracle Database 11gリリース1(11.1)以降、サーバー側ドライバにRowSetsサポートが追加されました。このため、Oracle Database 11gリリース1(11.1)からは、すべてのOracle JDBCドライバの型にわたり、RowSetサポートは均一です。標準のOracle JDBC Java Archive(JAR)ファイル、たとえば、ojdbc5.jarおよびojdbc6.jarにはoracle.jdbc.rowsetパッケージが含まれます。

注意:

- 接尾辞名の異なる他のJARファイル、たとえば、ojdbc5_g.jarおよびojdbc5dms.jarにも、oracle.jdbc.rowsetパッケージが含まれます。

- Oracle Database 10gリリース2(10.2)では、実装クラスはojdbc14.jarファイルにパッケージ化されていました。

- Oracle Database 10gリリース2(10.2)以前では、実装クラスはojdbc12.jarファイルにパッケージ化されていました。

- Oracleデータベース11gリリース1(11.1)以前は、RowSetsサポートはサーバー側ドライバでは利用できませんでした。

Oracle RowSet実装を使用するには、必要なRowSet型のパッケージからoracle.jdbc.rowsetパッケージ全体、または特定のクラスおよびインタフェースをインポートする必要があります。またクライアント側では、CLASSPATH環境変数にojdbc5.jarまたはojdbc6.jarなどのOracle JARファイルをインクルードする必要があります。

関連項目:
CLASSPATH環境変数の設定情報については、「環境変数の確認」を参照してください。

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

- RowSetのプロパティ

- イベントおよびイベント・リスナー

- コマンド・パラメータおよびコマンド実行

- RowSetの横断

RowSetのプロパティ

javax.sql.RowSetインタフェースは、単一のインタフェースでデータ・ソースのデータにアクセスするために変更できるJavaBeansプロパティ一式です。プロパティには、たとえば接続文字列、ユーザー名、パスワード、接続の種類および問合せ文字列があります。

プロパティおよびプロパティの説明の完全なリストは、Java2 Platform, Standard Edition(J2SE)のJavadocでjavax.sql.RowSetを参照してください。Javadocは、http://download.oracle.com/javase/1.5.0/docs/api/javax/sql/RowSet.htmlにあります。

このインタフェースは、プロパティ値の設定および取出しに必要な標準アクセッサ・メソッドを提供します。次のコードは、一部のRowSetプロパティを設定します。

...
rowset.setUrl("jdbc:oracle:oci:@");
rowset.setUsername("SCOTT");
rowset.setPassword("TIGER");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
...

この例では、URL、ユーザー名、パスワードおよびSQL問合せが、従業員番号、従業員名および全従業員の給与をRowSetオブジェクト内に取り出すためのRowSetプロパティとして設定されています。

イベントおよびイベント・リスナー

RowSetはJavaBeansイベントをサポートします。RowSetインタフェースは、次のタイプのイベントをサポートします。

- cursorMoved
このイベントはカーソルが移動するたびに生成されます。たとえば、nextメソッドまたはpreviousメソッドがコールされると生成されます。

- rowChanged
このイベントは、RowSetに行が挿入されるか、RowSetの行が更新されるか、またはRowSetから行が削除されると生成されます。

- rowSetChanged
このイベントは、RowSet全体が作成または変更されると生成されます。たとえば、executeメソッドがコールされると生成されます。

アプリケーション・コンポーネントでは、RowSetリスナーを実装し、これらのRowSetイベントをリスニングして、イベントの発生時に必要な操作を実行できます。これらのイベントに関係のあるアプリケーション・コンポーネントの場合は、標準のjavax.sql.RowSetListenerインタフェースを実装し、RowSetオブジェクトにこれらのリスナー・オブジェクトを登録する必要があります。リスナーの登録にはRowSet.addRowSetListenerメソッドを使用し、登録を解除するにはRowSet.removeRowSetListenerメソッドを使用します。複数のリスナーを同じRowSetオブジェクトに登録できます。

次のコードは、RowSetリスナーを登録します。

...
MyRowSetListener rowsetListener = new MyRowSetListener ();
// adding a rowset listener
rowset.addRowSetListener (rowsetListener);
...

次のコードは、リスナーを実装します。

public class MyRowSetListener implements RowSetListener
{
public void cursorMoved(RowSetEvent event)
{
// action on cursor movement
}

public void rowChanged(RowSetEvent event)
{
// action on change of row
}

public void rowSetChanged(RowSetEvent event)
{
// action on changing of rowset
}
}// end of class MyRowSetListener

選択されたイベントのみを処理するアプリケーションの場合、すべてのイベント処理メソッド用の空の実装を持つ抽象クラスであるoracle.jdbc.rowset.OracleRowSetListenerAdapterクラスを使用することにより、必要なイベント処理メソッドのみを実装することができます。次のコードでは、rowSetChangedイベントのみが処理され、残りのイベントは処理されません。

...
rowset.addRowSetListener(new oracle.jdbc.rowset.OracleRowSetListenerAdapter ()
{
public void rowSetChanged(RowSetEvent event)
{
// your action for rowSetChanged
}
}
);
...

コマンド・パラメータおよびコマンド実行

RowSetオブジェクトのcommandプロパティは、通常はSQL問合せ文字列を表し、処理時に実際のデータをRowSetオブジェクトに移入します。通常のJDBC処理と同様に、この問合せ文字列は入力やバインド・パラメータをとることができます。javax.sql.RowSetインタフェースにも、このSQL問合せに入力パラメータを設定するメソッドがあります。必要な入力パラメータが設定された後でSQL問合せが処理され、基礎となるデータ・ソースのデータをRowSetオブジェクトに移入できます。次のコードは、この単純な手順を示しています。

...
rowset.setCommand("SELECT ename, sal FROM emp WHERE empno = ?");
// setting the employee number input parameter for employee named "KING"
rowset.setInt(1, 7839);
rowset.execute();
...

前述の例では、従業員番号7839が、RowSetオブジェクトのcommandプロパティで指定されたSQL問合せの入力パラメータまたはバインド・パラメータとして設定されています。SQL問合せが処理されると、RowSetオブジェクトは、従業員番号7839の従業員の従業員名と給与情報で満たされます。

RowSetの横断

javax.sql.RowSetインタフェースは、java.sql.ResultSetインタフェースを拡張します。そのため、RowSetインタフェースでは、カーソル移動および位置指定の各メソッドがResulSetインタフェースから継承され、RowSetオブジェクト内のデータの横断に使用されます。継承されるメソッドの中には、absolute、beforeFirst、afterLast、nextおよびpreviousがあります。

RowSetインタフェースは、データを取得および更新するためのResultSetインタフェースと同じように使用できます。RowSetインタフェースでは、オプションでスクロール可能および更新可能な結果セットを実装できます。ResultSetインタフェースに含まれるすべてのフィールドおよびメソッドが、RowSetに実装されます。

注意:
java.sql.ResultSetインタフェースのスクロール可能で更新可能なプロパティは、ResultSetのOracle実装でも提供されます。

次のコードは、RowSetをスクロールする方法を示します。

/**
*  Scrolling forward, and printing the empno in
*  the order in which it was fetched.
*/
...
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
...
// going to the first row of the rowset
rowset.beforeFirst ();
while (rowset.next ())
System.out.println ("empno: " +rowset.getInt (1));

前述のコードでは、beforeFirstメソッドによって、カーソル位置がRowSetの最初の行の前に初期化されます。行は、nextメソッドを使用して前方方向に取り出されます。

次のコードは、RowSetを逆方向にスクロールする方法を示します。

/**
*  Scrolling backward, and printing the empno in
*  the reverse order as it was fetched.
*/
//going to the last row of the rowset
rowset.afterLast ();
while (rowset.previous ())
System.out.println ("empno: " +rowset.getInt (1));

前述の例では、RowSetの最後の行の後にカーソル位置が初期化されます。行は、RowSetのpreviousメソッドを使用して逆方向に取り出されます。

行の挿入、更新および削除は、結果セット機能と同様に行セット機能でもサポートされます。行セットを更新可能にするには、setReadOnly(false)およびacceptChangesの各メソッドをコールする必要があります。

次のコードは、行セットの5番目の位置に1行を挿入します。

...
/**
* Make rowset updatable
*/
rowset.setReadOnly (false);
/**
* Inserting a row in the 5th position of the rowset.
*/
// moving the cursor to the 5th position in the rowset
if (rowset.absolute(5))
{
rowset.moveToInsertRow ();
rowset.updateInt (1, 193);
rowset.updateString (2, "Ashok");
rowset.updateInt (3, 7200);

// inserting a row in the rowset
rowset.insertRow ();

// Synchronizing the data in RowSet with that in the database.
rowset.acceptChanges ();
}
...

前述の例では、パラメータ5が指定されたabsoluteメソッドをコールすることにより、RowSetの5番目の位置にカーソルが移動し、moveToInsertRowメソッドをコールすることにより、RowSetに新しい行を挿入するための場所が作成されます。新しく作成された行を更新するには、updateXXXメソッドを使用します。行のすべての列が更新されると、insertRowがコールされ、そのRowSetが更新されます。変更はacceptChangesメソッドを使用してコミットします。

CachedRowSet

CachedRowSetは、行がキャッシュされ、切断されている(つまり、データベースとのアクティブ接続を持たない)RowSetです。oracle.jdbc.rowset.OracleCachedRowSetクラスは、CachedRowSetのOracle実装です。Sun社のリファレンス実装と相互運用できます。ojdbc5.jarファイルおよびojdbc6.jarファイルのOracleCachedRowSetクラスは、標準のJSR-114インタフェースjavax.sql.rowset.CachedRowSetを実装します。

次のコードでは、OracleCachedRowSetオブジェクトを作成し、プロパティとしてRowSetオブジェクトの接続URL、ユーザー名、パスワードおよびSQL問合せを設定します。RowSetオブジェクトには、executeメソッドを使用してデータが移入されます。executeメソッドを処理した後、java.sql.ResultSetオブジェクトとしてRowSetオブジェクトを使用できるため、データの取得、スクロール、挿入、削除または更新を実行できます。

...
RowSet rowset = new OracleCachedRowSet();
rowset.setUrl("jdbc:oracle:oci:@");
rowset.setUsername("SCOTT");
rowset.setPassword("TIGER");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
while (rowset.next ())
{
System.out.println("empno: " +rowset.getInt (1));
System.out.println("ename: " +rowset.getString (2));
System.out.println("sal: "   +rowset.getInt (3));
}
...

問合せによりCachedRowSetオブジェクトにデータを移入するには、次の手順を実行します。

1. OracleCachedRowSetをインスタンス化します。

2. Url(接続URL)、Username、PasswordおよびCommand(問合せ文字列で、RowSetオブジェクトのプロパティ)を設定します。接続型を設定することもできますが、それはオプションです。

3. executeメソッドをコールして、CachedRowSetオブジェクトにデータを移入します。executeのコールにより、問合せセットがこのRowSetのプロパティとして実行されます。

OracleCachedRowSet rowset = new OracleCachedRowSet ();
rowset.setUrl ("jdbc:oracle:oci:@");
rowset.setUsername ("SCOTT");
rowset.setPassword ("TIGER");
rowset.setCommand ("SELECT empno, ename, sal FROM emp");
rowset.execute ();

populateメソッドを使用して、CachedRowSetオブジェクトに既存のResultSetオブジェクトを移入できます。これを行うには、次の手順を完了します。

1. OracleCachedRowSetをインスタンス化します。

2. すでに使用可能なResultSetオブジェクトをpopulateメソッドに渡して、RowSetオブジェクトにデータを移入します。

// Executing a query to get the ResultSet object.
ResultSet rset = pstmt.executeQuery ();

OracleCachedRowSet rowset = new OracleCachedRowSet ();
// the obtained ResultSet object is passed to the populate method
// to populate the data in the rowset object.
rowset.populate (rset);

前述の例では、問合せを実行してResultSetオブジェクトを取得し、そのResultSetオブジェクトがCachedRowSetオブジェクトのpopulateメソッドに渡されて、結果セットの内容がCachedRowSetに移入されています。

注意:
既存のResultSetオブジェクトをCachedRowSetオブジェクトへのデータの移入に使用する場合には、プロパティが適用される接続または結果セットがすでに作成されているため、トランザクションの分離や結果セットの同時実行性モードなどの接続プロパティおよびバインド・プロパティを設定することはできません。

次のコードは、OracleCachedRowSetオブジェクトをファイルに対してシリアライズしてから取得します。

// writing the serialized OracleCachedRowSet object
{
FileOutputStream fileOutputStream = new FileOutputStream("emp_tab.dmp");
ObjectOutputStream ostream = new ObjectOutputStream(fileOutputStream);
ostream.writeObject(rowset);
ostream.close();
fileOutputStream.close();
}

// reading the serialized OracleCachedRowSet object
{
FileInputStream fileInputStream = new FileInputStream("emp_tab.dmp");
ObjectInputStream istream = new ObjectInputStream(fileInputStream);
RowSet rowset1 = (RowSet) istream.readObject();
istream.close();
fileInputStream.close();
}

前述のコードでは、emp_tab.dmpファイル用にFileOutputStreamオブジェクトがオープンされ、データを移入されたOracleCachedRowSetオブジェクトがObjectOutputStreamを使用してこのファイルに書き込まれます。シリアライズされたOracleCachedRowSetオブジェクトは、FileInputStreamおよびObjectInputStreamオブジェクトを使用して取り出されます。

InputStream、OutputStream、バイナリ・ラージ・オブジェクト(BLOB)およびキャラクタ・ラージ・オブジェクト(CLOB)などの非シリアライズ形式のデータは、OracleCachedRowSetによってシリアライズされます。また、OracleCachedRowSetsは独自のメタデータを実装するため、追加のラウンドトリップを必要とせずに取得できます。次のコードは、RowSetのメタデータを取得する方法を示します。

...
ResultSetMetaData metaData = rowset.getMetaData();
int maxCol = metaData.getColumnCount();
for (int i = 1; i <= maxCol; ++i)
System.out.println("Column (" + i +") " + metaData.getColumnName(i));
...

OracleCachedRowSetクラスはシリアライズ可能なので、Remote Method Invocation(RMI)の場合と同様に、ネットワークや別のJava仮想マシン(JVM)の間で渡すことができます。OracleCachedRowSetクラスにデータが移入されると、任意のJVMまたはJDBCドライバを使用していない環境での移動が可能になります。RowSetにデータをコミットするには、JDBCドライバがインストールされている必要があります。

データを取得して、OracleCachedRowSetクラスでそれにデータを移入する処理の全体はサーバーで実行され、データを移入されたRowSetは、RMIやEnterprise Java Beans(EJB)などの適切なアーキテクチャを使用してクライアントに渡されます。クライアントは、取得、スクロール、挿入、更新および削除などすべての操作を、RowSet上で、データベースに接続しないで実行できます。データベースにデータがコミットされる場合は常に、RowSet内のデータとデータベース内のデータを同期させるacceptChangesメソッドがコールされます。このメソッドはJDBCドライバを利用するため、JVM環境にJDBC実装が含まれる必要があります。このアーキテクチャは、携帯情報端末(PDA)などのThinクライアントが関係するシステムに適しています。

CachedRowSetオブジェクトにデータを移入すると、このオブジェクトをResultSetオブジェクト、またはRMIやその他の適切なアーキテクチャを使用してネットワークを通じて渡すことが可能な他のオブジェクトとして使用できます。

CachedRowSetには、この他に次のような主要機能があります。

- RowSetのクローニング

- RowSetのコピーの作成

- RowSetの共有コピーの作成

CachedRowSetの制約事項

OracleCachedRowSetはシリアライズ可能なので、更新可能な結果セットに適用される、シリアライズ以外のすべての制約をここで適用できます。SQL問合せには、次の制約があります。

- データベース内の1つの表のみを参照できます。

- 結合操作は含まれません。

- 参照先の表の主キーを選択します。

また、新しい行を挿入するには、SQL問合せが次の条件を満たしている必要があります。

- 基礎となる表のNULL化可能でない列すべてを選択します。

- デフォルト値のないすべての列を選択します。

注意:
データはすべてメモリーにキャッシュされるため、CachedRowSetには大量のデータを格納できません。したがって、大量のデータを戻す可能性のあるOracleCachedRowSetを問合せで使用しないことをお薦めします。

結果セットのトランザクションの分離や同時実行性モードなど接続プロパティは、RowSetへのデータの移入後には設定できません。このプロパティは、データを取り出した後には接続に適用できないためです。

JdbcRowSet

JdbcRowSetは、ResultSetオブジェクトをラップするRowSetです。これは、接続RowSetであり、JavaBeanインタフェース形式のJDBCインタフェースを提供します。JdbcRowSetのOracle実装は、oracle.jdbc.rowset.OracleJDBCRowSetです。ojdbc5.jarファイルおよびojdbc6.jarファイルのOracleJDBCRowSetクラスは、標準のJSR-114インタフェースjavax.sql.rowset.JdbcRowSetを実装します。

表18-1は、JdbcRowSetインタフェースとCachedRowSetインタフェースの違いを示しています。

表18-1 JDBCのRowSetとCachedRowSetの比較

RowSetのタイプ

シリアライズ可能

データベースへの接続

JVM内での移動が可能

データベースに対するデータの同期化

JDBCドライバの存在

JDBC

あり

あり

なし

なし

あり

キャッシュ

あり

なし

あり

あり

なし

JdbcRowSetは接続されているRowSetで、データベースへのライブ接続を持ち、JdbcRowSet上のすべてのコールは、JDBC接続、文または結果セットのマッピング・コールに反映されます。CachedRowSetは、開いているデータベースへの接続をいっさい持ちません。

JdbcRowSetではJDBCドライバが存在する必要があるのに対して、CachedRowSetの場合は、操作時にJDBCドライバが存在する必要はありません。ただし、JdbcRowSetおよびCachedRowSetでは、RowSetへのデータ移入時とRowSetの変更をコミットするときには、JDBCドライバが必要です。

次のコードは、JdbcRowSetの使用方法を示します。

...
RowSet rowset = new OracleJDBCRowSet();
rowset.setUrl("java:oracle:oci:@");
rowset.setUsername("SCOTT");
rowset.setPassword("TIGER");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
while (rowset.next())
{
System.out.println("empno: " + rowset.getInt(1));
System.out.println("ename: " + rowset.getString(2));
System.out.println("sal: " + rowset.getInt(3));
}
...

前述の例では、接続URL、ユーザー名、パスワードおよびSQL問合せがRowSetオブジェクトのプロパティとして設定され、SQL問合せがexecuteメソッドを使用して処理され、行がRowSetオブジェクトに移入されたデータを横断して取得され出力されます。

WebRowSet

WebRowSetは、CachedRowSetの拡張機能です。このRowSetは一連のフェッチされる行または表データを表し、データソースとのアクティブな接続を保持せずに、各層およびコンポーネント間で渡すことができます。WebRowSetインタフェースは、結果セットの生成と使用をサポートし、結果セットとデータソースとの同期をExtensible Markup Language(XML)形式および接続切断方式の両方でサポートします。これにより、層と層をまたがり、またインターネット・プロトコルを介して、結果セットを移送できます。

WebRowSetのOracle実装は、oracle.jdbc.rowset.OracleWebRowSetです。このクラスは、ojdbc5.jarファイルおよびojdbc6.jarファイル内にあり、標準のJSR-114インタフェースjavax.sql.rowset.WebRowSetを実装します。このクラスは、oracle.jdbc.rowset.OracleCachedRowSetクラスも拡張します。OracleWebRowSetクラスは、OracleCachedRowSetクラスで使用可能なメソッドの他に、次のメソッドも提供します。

- public OracleWebRowSet() throws SQLException

これは、OracleWebRowSetオブジェクトの作成に使用するコンストラクタであり、OracleCachedRowSetオブジェクトのデフォルト値、デフォルトのOracleWebRowSetXmlReaderおよびデフォルトのOracleWebRowSetXmlWriterによって初期化されます。

- public void writeXml(java.io.Writer writer) throws SQLException
public void writeXml(java.io.OutputStream ostream) throws SQLException

これらのメソッドは、OracleWebRowSetオブジェクトを、提供されたWriterまたはOutputStreamオブジェクトにJSR-114 XMLスキーマ準拠のXML形式で書き込みます。RowSetデータの他に、RowSetのプロパティとメタデータも書き込まれます。

- public void writeXml(ResultSet rset, java.io.Writer writer) throws SQLException
public void writeXml(ResultSet rset, java.io.OutputStream ostream) throws SQLException

これらのメソッドは、OracleWebRowSetオブジェクトを作成し、そのオブジェクトに指定したResultSetオブジェクトのデータを移入し、提供されたWriterまたはOutputStreamオブジェクトにJSR-114 XMLスキーマ準拠のXML形式で書き込みます。

- public void readXml(java.io.Reader reader) throws SQLException
public void readXml(java.io.InputStream istream) throws SQLException

これらのメソッドは、提供されたReaderまたはInsputStreamオブジェクトを使用して、OracleWebRowSetオブジェクトをJSR-114 XMLスキーマ準拠のXML形式で読み取ります。

Oracle WebRowSet実装は、Java API for XML Processing (JAXP) 1.2をサポートしています。Simple API for XML (SAX) 2.0とDocument Object Model (DOM) JAXPのどちらに準拠しているXMLパーサーもサポートされます。WebRowSetのための現行のJSR-114 W3C XMLスキーマ(http://java.sun.com/xml/ns/jdbc/webrowset.xsd)に従います。

関連項目:

- JSR-114仕様: http://jcp.org/en/jsr/detail?id=114

- Java SE 5.0のJavadoc: http://download.oracle.com/javase/1.5.0/docs/api/

- Java SE 6.0のJavadoc: http://download.oracle.com/javase/6/docs/api/

readXml(...)メソッドを使用するアプリケーションの場合は、メソッドのコール前に、次の2つの標準JAXPシステム・プロパティのいずれかを設定する必要があります。

- javax.xml.parsers.SAXParserFactory
このプロパティは、SAXパーサー用です。

- javax.xml.parsers.DocumentBuilderFactory
このプロパティは、DOMパーサー用です。

次のコードでは、XML形式での書込みおよび読取り両方にOracleWebRowSetを使用します。

import java.sql.*;
import java.io.*;
import oracle.jdbc.rowset.*;

...
String url = "jdbc:oracle:oci8:@";

Connection conn = DriverManager.getConnection(url,"scott","tiger");
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select * from emp");

// Create an OracleWebRowSet object and populate it with the ResultSet object
OracleWebRowSet wset = new OracleWebRowSet();
wset.populate(rset);

try
{
// Create a java.io.Writer object
FileWriter out = new FileWriter("xml.out");

// Now generate the XML and write it out
wset.writeXml(out);
}
catch (IOException exc)
{
System.out.println("Couldn't construct a FileWriter");
}
System.out.println("XML output file generated.");

// Create a new OracleWebRowSet for reading from XML input
OracleWebRowSet wset2 = new OracleWebRowSet();

// Use Oracle JAXP SAX parser
System.setProperty("javax.xml.parsers.SAXParserFactory","oracle.xml.jaxp.JXSAXParserFactory");

try
{
// Use the preceding output file as input
FileReader fr = new FileReader("xml.out");

// Now read XML stream from the FileReader
wset2.readXml(fr);
}
catch (IOException exc)
{
System.out.println("Couldn't construct a FileReader");
}
...

注意:
前述のコードでは、スキーマの妥当性チェックをサポートするOracle SAX XMLパーサーを使用しています。

FilteredRowSet

FilteredRowSetは、WebRowSetの拡張機能であり、プログラム内容のフィルタリングに必要なプログラム・サポートを提供します。これにより、問合せの指定および関連処理に要するオーバーヘッドを回避できます。FilteredRowSetのOracle実装は、oracle.jdbc.rowset.OracleFilteredRowSetです。ojdbc5.jarファイルおよびojdbc6.jarファイルのOracleFilteredRowSetクラスは、標準のJSR-114インタフェースjavax.sql.rowset.FilteredRowSetを実装します。

OracleFilteredRowSetクラスは、次の新しいメソッドを定義します。

- public Predicate getFilter();

このメソッドは、OracleFilteredRowSetオブジェクトでアクティブなフィルタリング基準を定義するPredicateオブジェクトを戻します。

- public void setFilter(Predicate p) throws SQLException;

このメソッドは、Predicateオブジェクトをパラメータとして取ります。Predicateオブジェクトは、OracleFilteredRowSetオブジェクトに適用するフィルタリング基準を定義します。このメソッドでは、SQLException例外が発生します。

OracleFilteredRowSetオブジェクトに設定される条件は、参照できる行のセットを取得するためにオブジェクト内の行すべてに適用するフィルタリング基準を定義します。また、行の挿入、削除および変更に適用する基準も定義します。設定されたフィルタリング基準は、OracleFilteredRowSetオブジェクトの参照および更新すべてに適用されるゲーティング・メカニズムとして機能します。OracleFilteredRowSetオブジェクトを更新しようとすると、フィルタリング基準に違反するため、SQLException例外が発生します。

OracleFilteredRowSetオブジェクトに設定されているフィルタリング基準を変更するには、新しいPredicateオブジェクトを適用します。新しい基準は即時にオブジェクトに適用されるため、適用以後の参照および更新では、すべてこの新しい基準に準拠する必要があります。新しいフィルタリング基準を適用できるのは、OracleFilteredRowSetオブジェクトへの参照がない場合のみです。

オブジェクトに設定されたフィルタリング基準の範囲外の行は、そのフィルタリング基準が削除されるか、新しいフィルタリング基準が適用されるまで変更できません。また、このオブジェクトの同期化を続行しても、データソースと同期化される行は、フィルタリング基準の範囲内の行のみです。

次のコードは、OracleFilteredRowSetの使用例を示します。表test_tableに、NUMBER型のcol1およびcol2という2つの列があるものとします。この表からコードが取り出す行には、col1に50から100までの値、col2に100から200までの値が含まれています。

フィルタリング基準を定義する条件を次に示します。

public class PredicateImpl implements Predicate
{
private int low[];
private int high[];
private int columnIndexes[];

public PredicateImpl(int[] lo, int[] hi, int[] indexes)
{
low = lo;
high = hi;
columnIndexes = indexes;
}

public boolean evaluate(RowSet rs)
{
boolean result = true;
for (int i = 0; i < columnIndexes.length; i++)
{
int columnValue = rs.getInt(columnIndexes[i]);
if (columnValue < low[i] || columnValue > high[i])
result = false;
}
return result;
}

// the other two evaluate(...) methods simply return true

}

前述のコードで定義した条件を使用して、OracleFilteredRowSetオブジェクトの内容を次のようにフィルタリングします。

...
OracleFilteredRowSet ofrs = new OracleFilteredRowSet();
int low[] = {50, 100};
int high[] = {100, 200};
int indexes[] = {1, 2};
ofrs.setCommand("select col1, col2 from test_table");

// set other properties on ofrs like usr/pwd ...
...
ofrs.execute();
ofrs.setPredicate(new PredicateImpl(low, high, indexes));

// this will only get rows with col1 in (50,100) and col2 in (100,200)
while (ofrs.next()) {...}
...

JoinRowSet

JoinRowSetは、WebRowSetの拡張機能であり、異なるRowSetの関連データで構成されています。データソースに接続していない状態では、切断されたRowSet間でSQL JOINを確立する標準的な方法はありません。JoinRowSetはこの問題に対応しています。JoinRowSetのOracle実装は、oracle.jdbc.rowset.OracleJoinRowSetクラスです。このクラスは、ojdbc5.jarファイルおよびojdbc6.jarファイル内にあり、標準のJSR-114インタフェースjavax.sql.rowset.JoinRowSetを実装します。

Joinableインタフェースを実装する任意の数のRowSetオブジェクトは、SQL JOINに関連付けることが可能な場合、JoinRowSetオブジェクトに追加できます。RowSetの5つのタイプはすべて、Joinableインタフェースをサポートします。Joinableインタフェースには、JOINを実行するときに使用する列(一致する列)を指定するためのメソッドがあります。

一致する列は次の方法で指定できます。

- setMatchColumnメソッドの使用
このメソッドは、Joinableインタフェースで定義されます。RowSetオブジェクトをJoinRowSetオブジェクトに追加する前に、一致する列の設定に使用できるのは、このメソッドのみです。また、一致する列の再設定にいつでも使用できます。

- addRowSetメソッドの使用
このメソッドは、JoinRowSetでオーバーロードされます。このメソッドの5つの実装のうち4つは、一致する列をパラメータとして取ります。この4つのメソッドを使用して、RowSetオブジェクトをJoinRowSetオブジェクトに追加するときに、一致する列を設定または再設定できます。

OracleJoinRowSetは、継承されるメソッド以外に、次のメソッドを提供します。

- public void addRowSet(Joinable joinable) throws SQLException;
public void addRowSet(RowSet rowSet, int i) throws SQLException;
public void addRowSet(RowSet rowSet, String s) throws SQLException;
public void addRowSet(RowSet arowSet[], int an[]) throws SQLException;
public void addRowSet(RowSet arowSet[], String as[]) throws SQLException;

これらのメソッドを使用して、RowSetオブジェクトをOracleJoinRowSetオブジェクトに追加します。1つ以上のRowSetオブジェクトをOracleJoinRowSetオブジェクトに渡して追加できます。一致する列として設定する必要がある1つ以上の列の名前または索引を渡すこともできます。

- public Collection getRowSets() throws SQLException;

このメソッドは、OracleJoinRowSetに追加されたRowSetオブジェクトを取り出します。また、RowSetオブジェクトを含むjava.util.Collectionオブジェクトを戻します。

- public String[] getRowSetNames() throws SQLException;

このメソッドは、OracleJoinRowSetオブジェクトに追加されるRowSetオブジェクトの名前を含む文字列の配列を戻します。

- public boolean supportsCrossJoin();
public boolean supportsFullJoin();
public boolean supportsInnerJoin();
public boolean supportsLeftOuterJoin();
public boolean supportsRightOuterJoin();

これらのメソッドは、OracleJoinRowSetオブジェクトが、対応するJOIN型をサポートしているかどうかを示すブール値を戻します。

- public void setJoinType(int i) throws SQLException;

このメソッドを使用して、OracleJoinRowSetオブジェクトにJOIN型を設定します。このメソッドは、javax.sql.rowset.JoinRowSetインタフェースで定義されたJOIN型を指定する整数定数を取ります。

- public int getJoinType() throws SQLException;

このメソッドは、OracleJoinRowSetオブジェクトに設定されたJOIN型を示す整数値を戻します。このメソッドでは、SQLException例外が発生します。

- public CachedRowSet toCachedRowSet() throws SQLException;

このメソッドは、OracleJoinRowSetオブジェクトのデータを含むCachedRowSetオブジェクトを作成します。

- public String getWhereClause() throws SQLException;

このメソッドは、OracleJoinRowSetオブジェクトで使用されるWHERE句のSQLなどの記述を含む文字列を戻します。このメソッドでは、SQLException例外が発生します。

次のコードは、OracleJoinRowSetを使用して、2つの異なる表のデータを含む2つのRowSetで内部結合を実行します。結合されたRowSetには、2つの表で内部結合が実行された場合と同じデータが含まれます。表が2つあり、その一方はNUMBER型の2つの列Order_idおよびPerson_idを備えたOrder表、他方はNUMBER型の列Person_idとVARCHAR2型の列Nameを備えたPerson表であるものとします。

...
// RowSet holding data from table Order
OracleCachedRowSet ocrsOrder = new OracleCachedRowSet();
...
ocrsOrder.setCommand("select order_id, person_id from order");
...
// Join on person_id column
ocrsOrder.setMatchColumn(2);
ocrsOrder.execute();

// Creating the JoinRowSet
OracleJoinRowSet ojrs = new OracleJoinRowSet();
ojrs.addRowSet(ocrsOrder);

// RowSet holding data from table Person
OracleCachedRowSet ocrsPerson = new OracleCachedRowSet();
...
ocrsPerson.setCommand("select person_id, name from person");
...
// do not set match column on this RowSet using setMatchColumn().
//use addRowSet() to set match column
ocrsPerson.execute();

// Join on person_id column, in another way
ojrs.addRowSet(ocrsPerson, 1);

// now we can go the JoinRowSet as usual
ojrs.beforeFirst();
while (ojrs.next())
System.out.println("order id = " + ojrs.getInt(1) + ", " + "person id = " +
ojrs.getInt(2) + ", " + "person's name = " + ojrs.getString(3));
...

19 グローバリゼーション・サポート

Oracle Java Database Connectivity(JDBC)ドライバは、グローバリゼーション・サポート(以前のNational Language Support(NLS))を提供しています。グローバリゼーション・サポートにより、Oracleがサポートする任意のキャラクタ・セットで、データの取出しやデータベースへのデータの挿入が可能です。クライアントとサーバーで異なるキャラクタ・セットを使用する場合、ドライバでは、データベース・キャラクタ・セットとクライアント・キャラクタ・セット間の変換がサポートされます。

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

- グローバリゼーション・サポートの提供

- JDK 1.5のNCHAR、NVARCHAR2、NCLOBおよびdefaultNCharプロパティ

- JDK 1.6での各国語キャラクタ・セット用の新しいメソッド

関連項目:

- 「Oracle文字データ型のサポート」

- Oracle Databaseグローバリゼーション・サポート・ガイド

- 『Oracle Databaseリファレンス』

注意:

- Oracle Database 10g以上では、NLS_LANG変数がJDBCグローバリゼーション・メカニズムに組み込まれていません。JDBCドライバは、NLS環境をチェックしません。そのため、この変数を設定しても効果はありません。

- JDBCサーバー側内部ドライバは完全なグローバリゼーション・サポートを提供し、グローバリゼーション拡張ファイルを必要としません。

- JDBC 4.0には各国語キャラクタ・セットの値を読書きするためのメソッドが含まれています。JSE 6以上を使用する場合はこれらのメソッドを使用してください。

グローバリゼーション・サポートの提供

基本Javaアーカイブ(JAR)ファイル(ojdbc5.jarおよびojdbc6.jar)には、次の項目に対して完全なグローバリゼーション・サポートを提供するために必要なすべてのクラスが含まれています。

- Oracleオブジェクトまたはコレクション型のデータ・メンバーとして取得または挿入されないCHAR、VARCHAR、LONGVARCHARまたはCLOBデータ用のOracleキャラクタ・セット

- キャラクタ・セットUS7ASCII、WE8DEC、WE8ISO8859P1、WE8MSWIN1252およびUTF8に対するオブジェクトおよびコレクションのCHARまたはVARCHARデータ・メンバー

前述以外のキャラクタ・セットをオブジェクトまたはコレクションのCHARまたはVARCHARデータ・メンバーで使用するには、アプリケーションのCLASSPATH環境変数にorai18n.jarを含める必要があります。

注意:
以前のリリースでは、nls_charset12.zipファイルが必要でした。このファイルは現在使用されません。

orai18n.jarの縮小

orai18n.jarファイルには、多数の重要なキャラクタ・セットとグローバリゼーション・サポート・ファイルが含まれています。組込みのカスタマイズ・ツールを使用して、次のようにorai18n.jarファイルのサイズを縮小できます。

java -jar orai18n.jar -custom-charsets-jar [jar/zip_filename] -charset characterset_name [characterset_name ...]

たとえば、キャラクタ・セットJA16SJISおよびJA16EUCを含むカスタムのキャラクタ・セット・ファイルcustom_orai18n_ja.jarを作成する場合は、次のコマンドを発行します。

$ java -jar orai18n.jar -custom-charsets-jar custom_orai18n_ja.jar -charset JA16SJIS JA16EUC

コマンドの出力は次のとおりです。

Added Character set : JA16SJIS
Added Character set : JA16EUC

カスタムのJAR/ZIPファイルにファイル名を指定しない場合、jdbc_orai18n_cs.jarという名前のファイルが現行作業ディレクトリに作成されます。また、カスタムのJAR/ZIPファイルに、orai18nで始まる名前を指定することはできません。

無効またはサポートされていないキャラクタ・セットをコマンドに指定した場合、JAR/ZIPファイルは出力されません。カスタムのJAR/ZIPファイルは更新または削除されません。

カスタムのキャラクタ・セットJAR/ZIPはコマンドを受け入れません。ただし、バージョン情報およびJAR/ZIPファイルの生成に使用されたコマンドは出力されます。たとえば、jdbc_orai18n_cs.zipを設定した場合、情報を表示するコマンドおよび表示される情報は次のようになります。

$ java -jar jdbc_orai18n_cs.jar
Oracle Globalization Development Kit - 11.2.X.X.X Release
This custom character set jar/zip file was created with the following command:
java -jar orai18n.jar -custom-charsets-jar jdbc_orai18n_cs.jar -charset WE8ISO8859P15

指定できるキャラクタ・セットの数は、オペレーティング・システムのシェルまたはコマンド・プロンプトの制限によって決まります。サポートされているキャラクタ・セットはすべてコマンドで指定できます。

注意:
カスタム・キャラクタ・セットを使用する場合、JDBCがカスタム・キャラクタ・セットをサポートするためには、次の操作を実行する必要があります。

1. カスタム・キャラクタ・セットの作成プロセスで.nltおよび.nlbファイルを作成した後で、次のコマンドを使用して、新たに作成したキャラクタ・セットとlx0boot.nltファイルのために.glbファイルを作成します。

java -classpath $ORACLE_HOME/jlib/orai18n-tools.jar Ginstall <nlt file>

2. カスタム・キャラクタ・セットを使用してデータベースに接続するJDBCコードを実行する場合は、生成したファイルと$ORACLE_HOME/jlib/orai18n-mappings.jarをclasspath環境変数に追加します。

カスタム・キャラクタ・セット作成の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

JDK 1.5のNCHAR、NVARCHAR2、NCLOBおよびdefaultNCharプロパティ

デフォルトでは、oracle.jdbc.OraclePreparedStatementインタフェースにより、すべての列のデータ型は、列がデータベース・キャラクタ・セットでエンコードされるのと同じように処理されます。ただし、Oracle Database 10g以上では、oracle.jdbc.defaultNCharの値をtrueに設定すると、すべてのキャラクタ列がJDBCにより各国語として処理されます。

defaultNCharのデフォルト値はfalseです。defaultNCharの値がfalseである場合、特に各国語文字が必要な列のために、setFormOfUse(<column_Index>, OraclePreparedStatement.FORM_NCHAR)メソッドをコールする必要があります。たとえば、次のようになります。

PreparedStatement pstmt =
conn.prepareStatement("insert into TEST values(?,?,?)");
pstmt.setFormOfUse(1, OraclePreparedStatement.FORM_NCHAR);
pstmt.setString(1, myUnicodeString1); // NCHAR column
pstmt.setFormOfUse(2, OraclePreparedeStatement.FORM_NCHAR);
pstmt.setString(2, myUnicodeString2); // NVARCHAR2 column

defaultNCharの値をtrueと設定する場合、コマンドラインで次のように指定します。

java -Doracle.jdbc.defaultNChar=true myApplication

必要に応じて、アプリケーションでdefaultNCharを接続プロパティとして指定してNCHAR、NVARCHAR2またはNCLOBデータにアクセスすることもできます。

Properties props = new Properties();
props.put(OracleConnection.CONNECTION_PROPERTY_DEFAULTNCHAR, "true");
// set URL, username, password, and so on.
...
Connection conn = DriverManager.getConnection(props);

defaultNCharの値がtrueである場合、各国語文字が必要でない列のために、setFormOfUse(<column_Index>, FORM_CHAR)をコールする必要があります。たとえば、次のようになります。

PreparedStatement pstmt =
conn.prepareStatement("insert into TEST values(?,?,?)");
pstmt.setFormOfUse(3, OraclePreparedStatement.FORM_CHAR);
pstmt.setString(3, myString); // CHAR column

注意:

- 文字データには、必ずoracle.sql.CHARでなくjava.lang.Stringを使用します。CHARは下位互換性のみのために用意されています。

- setObjectメソッドを使用して各国語キャラクタ・セットにアクセスすることもできますが、setObjectメソッドを使用する場合、ターゲット・データ型をTypes.NCHAR、Types.NCLOB、Types.NVARCHARまたはTypes.LONGNVARCHARとして設定する必要があります。

注意:
Oracle Databaseでは、SQL文字列はデータベース・キャラクタ・セットに変換されます。そのため、次のことを覚えておく必要があります。

- Oracle Database 10gリリース1(10.1)以前のリリースでは、JDBCドライバは、データベース・キャラクタ・セットで表示できないUnicode文字を含むNCHARリテラル(n'...')をサポートしていません。データベース・キャラクタ・セットで表示できないUnicode文字はすべて破損します。

- Oracle Database 10gリリース2(10.2)のJDBCドライバがOracle Database 10gリリース2(10.2)のデータベース・サーバーに接続されている場合、NCHARリテラル(n'...')はすべてUnicodeリテラル(u'...')に変換され、ASCII以外の文字はすべて対応するUnicodeエスケープ・シーケンスに変換されます。この変換は、データ破損を防ぐために自動的に実行されます。

- Oracle Database 10gリリース2(10.2)のJDBCドライバがOracle Database 10gリリース1(10.1)以前のデータベース・サーバーに接続されている場合、NCHARリテラル(n'...')は変換されないため、データベース・キャラクタ・セットで表示できない文字はすべて破損します。

JDK 1.6での各国語キャラクタ・セット用の新しいメソッド

JDBC 4.0では、各国語キャラクタ・セット型にアクセスするために、次の4つの追加SQL型のサポートが導入されています。

- NCHAR

- NVARCHAR

- LONGNVARCHAR

- NCLOB

これらの型は、各国語キャラクタ・セットを使用して値がエンコードされる点を除き、CHAR、VARCHAR、LONGVARCHARおよびCLOB型に類似しています。JDBCの仕様では、Stringクラスを使用してNCHAR、NVARCHARおよびLONGNVARCHARデータを表し、NClobクラスを使用してNCLOB値を表します。

各国語の文字値を取得するには、アプリケーションから次のいずれかのメソッドをコールします。

- getNString

- getNClob

- getNCharacterStream

- getObject

各国語キャラクタ・タイプのパラメータ・マーカーの値を指定するには、アプリケーションから次のいずれかのメソッドをコールします。

- setNString

- setNCharacterStream

- setNClob

- setObject

注意:
setFormOfUseメソッドを使用して、JDK 1.6の各国語キャラクタ値を指定できます。しかし、このメソッドは今後のリリースで非推奨になるため、利用はお薦めしません。この項で説明したメソッドを使用することをお薦めします。

ヒント:
setObjectメソッドが使用される場合、ターゲット・データ型をTypes.NCHAR、Types.NCLOB、Types.NVARCHARまたはTypes.LONGNVARCHARとして設定する必要があります。

第V部

パフォーマンスとスケーラビリティ

第V部では、文キャッシュ、暗黙的接続キャッシュ、実行時接続ロード・バランシング、Oracle Call Interface(OCI)接続プーリングなど、Oracle Java Database Connectivity(JDBC)のパフォーマンス強化機能について説明します。また、バッチ更新や行のプリフェッチなどのOracleパフォーマンス拡張機能についても説明します。

第V部の構成は次のとおりです。

- 第20章「文キャッシュと結果セット・キャッシュ」

- 第21章「暗黙的接続キャッシュ」

- 第22章「実行時接続ロード・バランシング」

- 第23章「パフォーマンス拡張要素」

- 第24章「OCI接続プーリング」

- 第25章「Oracleアドバンスト・キューイング(AQ)」

- 第26章「データベース変更通知」

20 文キャッシュと結果セット・キャッシュ

この章では、Oracle Java Database Connectivity(JDBC)拡張要素である文キャッシュの利点と使用方法について説明します。

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

- 文キャッシュについて

- 文キャッシュの使用方法

- 文オブジェクトの再利用

- 結果セット・キャッシュ

注意:
Oracle9iリリース2(9.2)以上では、Oracle9iリリース1(9.0.1)でサポートされていたApplication Program Interface(API)にかわり、Oracle JDBCによって、新しい文キャッシュ・インタフェースと実装が提供されています。以前のAPIは非推奨となりました。

文キャッシュについて

文キャッシュにより、繰り返しコールされるループやメソッドなどで何度も使用する実行文がキャッシュされるため、パフォーマンスが向上します。JDBC 3.0以降では、JDBC標準で文キャッシュ・インタフェースが定義されています。

文キャッシュでは、次のことができます。

- カーソル作成の繰返しによるオーバーヘッドを回避します。

- 文の解析と作成の繰返しを回避します。

- クライアント内のデータ構造を再利用します。

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

- 文キャッシュの基本

- 暗黙的文キャッシュ

- 明示的文キャッシュ

注意:
暗黙的文キャッシュの使用を強くお薦めします。Oracle JDBCドライバは暗黙的文キャッシュが有効になっているという前提で設計されています。このため、文キャッシュを使用しないとパフォーマンスに悪影響を及ぼします。

文キャッシュの基本

アプリケーションでは、特定の物理接続に関連付けられている文をキャッシュするために文キャッシュを使用します。このキャッシュはOracleConnectionオブジェクトに関連付けられています。OracleConnectionには、文キャッシュを有効にするメソッドが含まれています。文キャッシュを有効にすると、closeメソッドをコールするときに文オブジェクトがキャッシュされます。

物理接続ごとに独自のキャッシュがあるため、複数の物理接続に対して文キャッシュを有効にすると複数のキャッシュが存在することになります。接続キャッシュで文キャッシュを有効にすると、基礎となる物理接続で有効な文キャッシュが論理接続で利用されます。接続キャッシュによって保持されている論理接続で文キャッシュを有効にしようとすると、例外が発生します。

文キャッシュには、暗黙的文キャッシュと明示的文キャッシュの2つのタイプがあります。文キャッシュの各タイプは、互いに関係なく有効または無効にできます。いずれかを有効にするか、いずれも有効にしないか、または両方とも有効にすることができます。両方のタイプの文キャッシュで、接続ごとに1つのキャッシュが共有されます。

暗黙的文キャッシュ

暗黙的文キャッシュを有効にすると、JDBCでは、プリコンパイルされたSQL文またはコール可能文の文オブジェクトのcloseメソッドをコールしたときに、その文が自動的にキャッシュされます。プリコンパイルされたSQL文およびコール可能文のキャッシュおよび取出しには、標準の接続オブジェクトおよび文オブジェクト・メソッドを使用します。

暗黙的文キャッシュはSQL文字列をキーとして使用しますが、プレーン文はSQL文字列を使用せずに作成されるため、プレーン文は暗黙的にキャッシュされません。このため、暗黙的文キャッシュは、SQL文字列を使用して作成されるOraclePreparedStatementおよびOracleCallableStatementオブジェクトにのみ適用されます。OracleStatementとともに暗黙的文キャッシュを使用することはできません。OraclePreparedStatementまたはOracleCallableStatementを作成するとき、JDBCドライバはキャッシュを自動的に検索し、一致する文を探します。一致基準は、次のとおりです。

- 文内のSQL文字列は、キャッシュのSQL文字列と同一である必要があります。

- 文の種類は、同じにする必要があります。つまり、プリコンパイルされたSQL文またはコール可能文にします。

- 文によって生成される結果セットのスクロール可能な型は、同じにする必要があります。つまり、forward-onlyまたはscrollableにします。

キャッシュ検索中に一致するものが見つかった場合は、キャッシュされた文が戻されます。一致するものが見つからなかった場合は、新しい文が作成されて戻されます。どちらの場合でも、文は、そのカーソルおよび状態とともに、文オブジェクトのcloseメソッドをコールするとキャッシュされます。

キャッシュされたOraclePreparedStatementまたはOracleCallableStatementオブジェクトが取り出されると、状態およびデータ情報は自動的に再初期化されて、デフォルト値にリセットされますが、メタデータは保存されます。最大サイズに準拠するため、最低使用頻度(LRU)アルゴリズムを使用してキャッシュから文が削除されます。

注意:
JDBCドライバは、メタデータを消去しません。メタデータはパフォーマンスの理由から保存されますが、セマンティクスへの影響はありません。暗黙的キャッシュによる文は、新たに作成された場合と同様に動作します。

特定の文を暗黙的なキャッシュの対象から外すことができます。

関連項目:
「特定の文に対する暗黙的文キャッシュの無効化」

明示的文キャッシュ

明示的文キャッシュによって、プリコンパイルされたSQL文およびコール可能文を選択してキャッシュし、取り出すことができます。明示的文キャッシュは、ユーザーが指定する任意のJava Stringであるキーに依存します。

注意:
プレーン文はキャッシュできません。

明示的文キャッシュは文のデータ、状態およびメタデータを保持するため、メタデータのみを保持する暗黙的文キャッシュに対してパフォーマンス上は有利です。ただし、このタイプのキャッシュを使用する場合は慎重である必要があります。明示的文キャッシュは再利用のために3つの種類の情報をすべて保存するため、前回の文の使用から、どのようなデータと状態が保持されているかわからない場合があります。

暗黙的文キャッシュと明示的文キャッシュは次の点が異なります。

- 文の取出し
暗黙的文キャッシュの場合は、文をキャッシュから取り出すための特別な処理は不要です。かわりに、prepareStatementまたはprepareCallをコールするたびに、JDBCでは一致する文についてキャッシュが自動的にチェックされ、見つかった場合はその文が戻されます。しかし、明示的文キャッシュの場合は、専用のOracle WithKeyメソッドを使用して、文オブジェクトをキャッシュし、取り出します。

- キーの指定
暗黙的文キャッシュでは、プリコンパイルされたSQL文またはコール可能文のSQL文字列がキーとして使用され、ユーザーは特にアクションを実行する必要はありません。これに対し明示的文キャッシュでは、キーとして使用するJava Stringを指定する必要があります。

- 文の戻り
暗黙的文キャッシュの実行中に、JDBCドライバでキャッシュ内に一致する文を見つけられない場合は、新しい文が自動的に作成されます。しかし、明示的文キャッシュの実行中にJDBCドライバでキャッシュ内に一致する文を見つけられない場合は、NULL値が戻されます。

表20-1で、暗黙的文キャッシュと明示的文キャッシュで使用されるメソッドの違いを比較します。

表20-1 文キャッシュで使用されるメソッドの比較

割当て

キャッシュへの挿入

キャッシュからの取出し

暗黙的

prepareStatement prepareCall

close

prepareStatement prepareCall

明示的

createStatement prepareStatement prepareCall

closeWithKey

getStatementWithKey getCallWithKey

文キャッシュの使用方法

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

- 文キャッシュの有効化および無効化

- キャッシュされた文のクローズ

- 暗黙的文キャッシュの使用方法

- 明示的文キャッシュの使用方法

文キャッシュの有効化および無効化

OracleConnection APIを使用する場合は、暗黙的および明示的な文キャッシュは、互いに関係なく有効または無効にできます。いずれかを有効にするか、いずれも有効にしないか、または両方とも有効にすることができます。

暗黙的文キャッシュの有効化

暗黙的文キャッシュを有効にする方法は2つあります。最初のメソッドは、プールされていない物理接続上で文キャッシュを有効にします。ここでは、setStatementCacheSize メソッドを使用して、すべての接続に対する文サイズを明示的に指定する必要があります。2番目のメソッドは、プールされている論理接続上で文キャッシュを有効にします。プール内のそれぞれの接続は、MaxStatementsLimitプロパティを設定することで指定できる最大サイズが同一である、独自の文キャッシュを持っています。

方法1

次の手順を実行します。

- 接続でOracleDataSource.setImplicitCachingEnabled(true)メソッドをコールして、OracleDataSourceプロパティimplicitCachingEnabledをtrueに設定します。たとえば、次のようになります。

OracleDataSource ods =  new OracleDataSource();
...
ods.setImplicitCachingEnabled(true);
...

- 物理接続でOracleConnection.setStatementCacheSizeメソッドをコールします。引数にはキャッシュ内の文の最大数を指定します。たとえば、次のコードでは、キャッシュ・サイズを10の文に指定します。

((OracleConnection)conn).setStatementCacheSize(10);

方法2

次の手順を実行します。

- OracleDataSourceプロパティのimplicitCachingEnabledおよびconnectionCachingEnabledをtrueに設定します。たとえば、次のようになります。

OracleDataSource ods =  new OracleDataSource();
...
ods.setConnectionCachingEnabled( true );
ods.setImplicitCachingEnabled( true );
...

- 接続キャッシュを使用する場合は、接続キャッシュでMaxStatementsLimitプロパティを正の整数に設定します。たとえば、次のようになります。

Properties cacheProps = new Properties();
...
cacheProps.put( "MaxStatementsLimit", "50" );

暗黙的キャッシュが有効になっているかどうかを判断するには、getImplicitCachingEnabledをコールします。暗黙的キャッシュが有効な場合はtrueが、それ以外の場合はfalseが戻されます。

注意:
文キャッシュを有効にすると、暗黙的文キャッシュと明示的文キャッシュの両方が有効になります。

暗黙的文キャッシュの無効化

暗黙的文キャッシュを無効にするには、接続でsetImplicitCachingEnabled(false)をコールするか、またはImplicitCachingEnabledプロパティをfalseに設定します。

明示的文キャッシュの有効化

明示的文キャッシュを有効にするには、最初に文キャッシュ・サイズを設定する必要があります。キャッシュ・サイズを設定するために、物理接続でOracleConnection.setStatementCacheSizeをコールします。引数にはキャッシュ内の文の最大数を指定します。0(ゼロ)を指定すると、キャッシングは行われません。キャッシュ・サイズのチェックには、次のようにgetStatementCacheSizeメソッドを使用します。

System.out.println("Stmt Cache size is " +
((OracleConnection)conn).getStatementCacheSize());

次のコードでは、キャッシュ・サイズを10の文に指定します。

((OracleConnection)conn).setStatementCacheSize(10);

接続でsetExplicitCachingEnabled(true)をコールすることにより、明示的文キャッシュを有効にします。

明示的キャッシュが有効になっているかどうかを判断するには、getExplicitCachingEnabledをコールします。明示的キャッシュが有効な場合はtrueが、それ以外の場合はfalseが戻されます。

注意:

- 特定の物理接続に対しては、暗黙的キャッシュと明示的キャッシュを別々に有効にします。このため、同じセッション中で暗黙的文キャッシュと明示的文キャッシュの両方を実行できるわけです。

- 暗黙的文キャッシュと明示的文キャッシュは、同一のキャッシュを共有します。文キャッシュのサイズ設定では、この点を考慮してください。

明示的文キャッシュの無効化

setExplicitCachingEnabled(false)をコールすることにより、明示的文キャッシュを無効にします。キャッシュを無効化またはクローズすると、そのキャッシュは消去されます。次の例では、明示的文キャッシュを無効にします。

((OracleConnection)conn).setExplicitCachingEnabled(false);

キャッシュされた文のクローズ

文をクローズし、それが確実にキャッシュに戻されないようにするには次の操作を行います。

J2SE 5.0の場合

- その文のキャッシュを無効にします。

stmt.setDisableStatementCaching(true);

- 文オブジェクトのcloseメソッドをコールします。

stmt.close();

JSE 6.0の場合

stmt.setPoolable(false);
stmt.close();

キャッシュされた文の物理的なクローズ

暗黙的文キャッシュを有効にすると、文の物理的なクローズを手動で実行できなくなります。文オブジェクト・キャッシュのcloseメソッドは、文をクローズするのではなく、キャッシュします。文は、次の3つの条件の1つで自動で物理的にクローズされます。

- 関連付けられている接続がクローズされた場合

- キャッシュがそのサイズ制限に達し、LRUアルゴリズムにより、最低使用頻度の文オブジェクトが優先的に取得される場合

- 文キャッシュが無効にされている文でcloseメソッドをコールした場合

暗黙的文キャッシュの使用方法

暗黙的文キャッシュを有効にすると、デフォルトではすべてのプリコンパイルされたSQL文およびコール可能文が自動的にキャッシュされます。暗黙的文キャッシュでは、次の手順が実行されます。

1. 暗黙的文キャッシュを有効にします。

2. 標準メソッドの1つを使用して文を割り当てます。

3. キャッシュの対象としない特定の文に対する暗黙的文キャッシュを無効にします。これは省略可能な手順です。

4. closeメソッドを使用して文をキャッシュします。

5. 暗黙的にキャッシュされた文を取り出すには、適切な標準のprepareメソッドをコールします。

暗黙的キャッシュのための文の割当て

暗黙的文キャッシュに文を割り当てるには、通常prepareStatementまたはprepareCallメソッドを使用します。

次のコードでは、pstmtと呼ばれる新しい文オブジェクトを割り当てます。

PreparedStatement pstmt = conn.prepareStatement    ("UPDATE emp SET ename = ? WHERE rowid = ?");

特定の文に対する暗黙的文キャッシュの無効化

ある接続の暗黙的文キャッシュを有効にすると、デフォルトでは、その接続のすべてのコール可能文およびプリコンパイルされたSQL文が自動的にキャッシュされます。特定のコール可能文またはプリコンパイルされたSQL文が暗黙的にキャッシュされないようにするには、文オブジェクトのsetDisableStatementCachingメソッドを使用します。キャッシュ領域を管理するためには、使用頻度の低い文でsetDisableStatementCachingメソッドをコールします。

次のコードでは、pstmtに対する暗黙的文キャッシュを無効にします。

PreparedStatement pstmt = conn.prepareStatement("SELECT 1 from DUAL");
((OraclePreparedStatement)pstmt).setDisableStmtCaching(true);
pstmt.close ();

注意:
JSE 6を使用している場合は、標準JDBC 4.0メソッドsetPoolableを使用して文キャッシュを無効にします。

PreparedStatement.setPoolable(false);

次のコマンドを使用してStatementオブジェクトがプール可能かどうかを確認します。

Statement.isPoolable();

文の暗黙的なキャッシュ

割り当てられた文をキャッシュするには、文オブジェクトのcloseメソッドをコールします。OraclePreparedStatementまたはOracleCallableStatementオブジェクトでcloseメソッドをコールすると、この文のキャッシュを無効にしていないかぎり、JDBCドライバではこの文がキャッシュ内に自動的に挿入されます。

次のコードでは、pstmt文をキャッシュします。

pstmt.close ();

暗黙的にキャッシュされた文の取出し

暗黙的にキャッシュされた文を取り出すには、文の種類に応じて、prepareStatementまたはprepareCallメソッドをコールします。

次のコードでは、prepareStatementメソッドを使用して、キャッシュからpstmtを取り出します。

pstmt = conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");

文を割り当てたり、暗黙的にキャッシュされた文を取り出したりするメソッドについて、表20-2で説明します。

表20-2 文の割当ておよび暗黙的文キャッシュで使用されるメソッド

メソッド

暗黙的文キャッシュの機能

prepareStatement

目的のキャッシュされたOraclePreparedStatementオブジェクトを検索して戻すキャッシュ検索を実行します。一致するオブジェクトが見つからない場合は、新しいOraclePreparedStatementオブジェクトを割り当てます。

prepareCall

目的のキャッシュされたOracleCallableStatementオブジェクトを検索して戻すキャッシュ検索を実行します。一致するオブジェクトが見つからない場合は、新しいOracleCallableStatementオブジェクトを割り当てます。

例20-1は、暗黙的文キャッシュを有効にする方法を示すサンプル・コードです。

例20-1 暗黙的文キャッシュの使用

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.pool.OracleDataSource;
public class TestJdbc
{
/**
* Get a Connection, prepare a statement, execute a query, fetch the results, close the connection.
* @param ods the DataSource used to get the connection.
*/
private static void doSQL( DataSource ods ) throws SQLException
{
final String SQL = "select username from all_users";
OracleConnection  conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = (OracleConnection) ods.getConnection();
System.out.println( "Connection:" + conn );
System.out.println( "Connection getImplicitCachingEnabled:" + conn.getImplicitCachingEnabled() );
System.out.println( "Connection getStatementCacheSize:" + conn.getStatementCacheSize() );
ps = conn.prepareStatement( SQL );
System.out.println( "PreparedStatement:" + ps );
rs = ps.executeQuery();
while ( rs.next() )
{
String owner = rs.getString( 1 );
System.out.println( owner );
}
}
finally
{
if ( rs != null )
{
rs.close();
}
if ( ps != null )
{
ps.close();
conn.close();
}
}
}
public static void main( String[] args )
{
try
{
OracleDataSource ods =  new OracleDataSource();
ods.setDriverType( "thin" );
ods.setServerName( "localhost" );
ods.setPortNumber( 1521 );
ods.setServiceName( "orcl" );
ods.setUser( "scott" );
ods.setPassword( "tiger" );
ods.setConnectionCachingEnabled( true );
ods.setImplicitCachingEnabled( true );
Properties cacheProps = new Properties();
cacheProps.put( "InitialLimit", "1" );
cacheProps.put( "MinLimit", "1" );
cacheProps.put( "MaxLimit", "5" );
cacheProps.put( "MaxStatementsLimit", "50" );
ods.setConnectionCacheProperties( cacheProps );
System.out.println( "DataSource getImplicitCachingEnabled: " + ods.getImplicitCachingEnabled() );
for ( int i = 0; i < 5; i++ )
{
doSQL( ods );
}
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
}

明示的文キャッシュの使用方法

明示的文キャッシュを有効にすると、プリコンパイルされたSQL文またはコール可能文を明示的にキャッシュできます。明示的文キャッシュでは、次の処理が行われます。

1. 明示的文キャッシュを有効にします。

2. 標準メソッドの1つを使用して文を割り当てます。

3. 文を明示的にキャッシュするには、closeWithKeyメソッドを使用して、キーを付けてその文をクローズします。

4. 明示的にキャッシュされた文を取り出すには、適切なWithKeyメソッドをコールして、適切なキーを指定します。

5. オープンしている、明示的にキャッシュされた文を再キャッシュするには、closeWithKeyメソッドを使用して文を再度クローズします。キャッシュされた文をクローズするたびに、そのキーを使用して文を再キャッシュします。

明示的なキャッシュのための文の割当て

明示的文キャッシュに文を割り当てるには、通常createStatement、prepareStatementまたはprepareCallメソッドを使用します。

次のコードでは、pstmtと呼ばれる新しい文オブジェクトを割り当てます。

PreparedStatement pstmt =    conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");

文の明示的なキャッシュ

割り当てられた文を明示的にキャッシュするには、文オブジェクトのcloseWithKeyメソッドをコールして、キーを指定します。キーは、ユーザーが指定する任意のJava Stringです。closeWithKeyメソッドは、文をそのままキャッシュします。つまり、データ、状態およびメタデータは消去されずに保持されます。

次のコードでは、"mykey"キーを使用してpstmt文をキャッシュします。

((OraclePreparedStatement)pstmt).closeWithKey ("mykey");

明示的にキャッシュされた文の取出し

明示的にキャッシュされた文を再度コールするには、文の種類によって、getStatementWithKeyまたはgetCallWithKeyメソッドをコールします。

指定したキーを使用して文を取り出す場合は、指定したキーに基づいて、JDBCドライバがキャッシュ内でその文を検索します。一致する文が見つかった場合、一致する文は、状態、データおよびメタデータとともに戻されます。情報は、文が最後にクローズしたときの状態で戻されます。一致する文が見つからない場合は、JDBCドライバでnullが戻されます。

次のコードでは、getStatementWithKeyメソッドで"mykey"キーを使用して、キャッシュからpstmtを再度コールします。pstmt文オブジェクトは"mykey"キーでキャッシュされていました。

pstmt = ((OracleConnection)conn).getStatementWithKey ("mykey");

pstmt文オブジェクトでcreationStateメソッドをコールすると、メソッドはEXPLICITを戻します。

重要:
明示的にキャッシュされた文を取り出す場合は、キーを指定するときに文の種類に適したメソッドを使用してください。たとえば、prepareStatementメソッドを使用して文を割り当てた場合は、getStatementWithKeyメソッドを使用してキャッシュから文を取り出します。JDBCドライバは、戻す文の型を検証しません。

明示的にキャッシュされた文を取り出す場合に使用するメソッドについて、表20-3で説明します。

表20-3 明示的にキャッシュされた文を取り出す場合に使用するメソッド

メソッド

明示的文キャッシュの機能

getStatementWithKey

キャッシュからプリコンパイルされたSQL文を取り出すのに必要なキーを指定します。

getCallWithKey

キャッシュからコール可能文を取り出すのに必要なキーを指定します。

文オブジェクトの再利用

JDBC 3.0の仕様で導入された文プーリングでは、アプリケーションは、Connectionオブジェクトの使用と同様にしてPreparedStatementオブジェクトを再利用することができます。PreparedStatementオブジェクトは、複数の論理接続が透過的に再利用できます。

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

- プールされた文の使用

- プールされた文のクローズ

注意:
Oracle JDBCドライバでは、文のプーリングをサポートするために、暗黙的文キャッシュを使用します。

プールされた文の使用

StatementインタフェースからisPoolableメソッドをコールすることによって、データソースが文プーリングをサポートするかどうかを認識できます。戻り値がtrueの場合、アプリケーションはPreparedStatementオブジェクトがプールされていることを認識しています。アプリケーションはまた、StatementインタフェースからsetPoolableメソッドをコールすることによって、文がプールされるようにするかどうかを指定することができます。

プールされた文の再利用は、アプリケーションに対して完全に透過的である必要があります。つまり、PreparedStatementオブジェクトが文プーリングに関与するかどうかにかかわらず、アプリケーション・コードが同じままであることが必要です。アプリケーションがPreparedStatementオブジェクトをクローズした場合、再利用する際はConnection.prepareStatementメソッドをコールする必要があります。

注意:
アプリケーションは、文がどのようにプールされるかを、直接的に制御しません。文のプールはPooledConnectionオブジェクトに関連付けられます。このオブジェクトの動作は、それを作成したConnectionPoolDataSourceオブジェクトのプロパティによって決定されます。

プールされた文のクローズ

アプリケーションがプールされた文をクローズする方法は、プールされていない文をクローズする方法と完全に同じです。プールされた文であってもプールされていない文であっても、一度クローズされると、その文をアプリケーションが使用することはできず、再利用しようとすると例外がスローされる原因になります。認識できる唯一の相違点は、プールされる物理文をアプリケーションが直接クローズすることができないということです。その操作はプール・マネージャが行います。メソッドPooledConnection.closeAllは、指定の物理接続上でオープンしている文をすべてクローズします。これにより、それらの文に関連付けられているリソースが解放されます。

次のメソッドは、プールされた文をクローズすることができます。

- close
このjava.sql.Statementインタフェース・メソッドはアプリケーションによってコールされます。文がプールされる場合、アプリケーションが使用する論理文はクローズされますが、プールされた物理文はクローズされません。

- close
このjava.sql.Connectionインタフェース・メソッドはアプリケーションによってコールされます。このメソッドは、文を使用する接続がプールされるかどうかに応じて、異なる動作をします。

- プールされていない接続
このメソッドは、物理接続が作成したすべての接続とすべての文をクローズします。こうする必要があるのは、外部的に管理されているリソースをいつ解放できるかは、ガーベジ収集メカニズムで検出できないためです。

- プールされた接続
このメソッドは論理接続とそれが戻した論理文をクローズしますが、その基礎となるPooledConnectionオブジェクトや、関連付けられているプールされた文はオープンされた状態に残します。

- PooledConnection.closeAll
このメソッドは、PooledConnectionオブジェクトによってプールされる物理文をすべてクローズするために接続プール・マネージャによってコールされます。

結果セット・キャッシュ

アプリケーションでは、データベースに問合せを繰返し送信することがあります。繰返しの問合せのレスポンス時間を改善するには、問合せの結果、問合せフラグメントおよびPL/SQLファンクションをメモリーにキャッシュできます。結果キャッシュには、すべてのセッションにわたって共有される問合せの結果が格納されます。これらの問合せを繰返し実行すると、結果がキャッシュ・メモリーから直接取り出されます。

結果が問合せ結果キャッシュに格納されることを示すには、問合せまたは問合せフラグメントに結果キャッシュのヒントで注釈を付ける必要があります。

問合せ結果セットは、次の方法でキャッシュできます。

- サーバー側キャッシュ

- クライアント結果キャッシュ

注意:

- サーバー側およびクライアント結果セットのキャッシュは、読取り専用または大部分が読取りのデータに最も便利です。非常に動的な結果となる問合せの場合は、パフォーマンスが低下する可能性があります。

- サーバー側およびクライアント結果セットのキャッシュはどちらも、メモリーを使用します。したがって、非常に大きな結果セットをキャッシュすると、パフォーマンス上の問題が発生する可能性があります。

サーバー側キャッシュ

サーバー側結果セット・キャッシュは、Oracle Database 11gリリース1(11.1)から、JDBC ThinおよびJDBC Oracle Call Interface(OCI)の両方のドライバに対してサポートされるようになりました。サーバー側結果キャッシュは、現在の問合せ、問合せフラグメントおよびPL/SQLファンクションの結果をメモリーにキャッシュし、その問合せ、問合せフラグメントまたはPL/SQLファンクションをその後実行する際に、キャッシュした結果を使用するためのものです。キャッシュした結果はSGAの結果キャッシュ・メモリー部分に存在します。結果キャッシュを作成したときに使用されたデータベース・オブジェクトが正常に変更されると、キャッシュされた結果は自動的に無効になります。サーバー側キャッシュには、次の2つのタイプがあります。

- SQL問合せ結果キャッシュ

- PL/SQLファンクション結果キャッシュ

関連項目:

- SQL問合せ結果キャッシュの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

- PL/SQLファンクション結果キャッシュの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

クライアント結果キャッシュ

Oracle Database 11gリリース1(11.1)から、JDBC OCIドライバーに対してクライアント結果キャッシュがサポートされるようになりました。クライアント結果キャッシュは、問合せ結果セットをキャッシュすることで、次回以降の問合せ実行がサーバーから行をフェッチせずキャッシュされた結果にアクセスすることを可能にし、アプリケーションのパフォーマンスを改善します。これにより、キャッシュされた結果を取り出すためにサーバーに何度もラウンドトリップを行うことがなくなり、サーバーのCPUの使用量が減少します。クライアント結果キャッシュでは、キャッシュされた結果セットに影響を与える可能性のあるすべてのセッション状態やデータベース変更と一致するように、結果セットを透過的に維持します。これにより、回数の多いクライアントのSQL問合せ実行や行のフェッチでの応答時間が大幅に改善されます。消費されるCPU時間が減少するため、サーバーでのスケーラビリティは向上します。

関連項目:
「クライアント結果キャッシュ」

21 暗黙的接続キャッシュ

一般に中間層で実装される接続キャッシュは、物理データベース接続のキャッシュを維持し、使用するための手段です。

注意:
Oracle Database 11gリリース2 (11.2)から、この機能は非推奨となり、Universal Connection Pool (UCP) for JDBCがこれに置き換わりました。新しいアーキテクチャは、以前より強力でパフォーマンスも向上しているため、こちらを使用することをお薦めします。詳細は、次のリンクを参照してください。

http://www.oracle.com/technology/tech/java/sqlj_jdbc/index.html

暗黙的接続キャッシュは、Java Database Connectivity(JDBC)3.0に準拠した、DataSource用の接続キャッシュの実装です。キャッシュへの透過的アクセス、複数ユーザーのサポート、およびユーザー定義のプロファイルに基づいて接続を要求できる機能は、JavaおよびJava2 Platform, Enterprise Edition(J2EE)アプリケーションに対して役立ちます。

アプリケーションは、OracleDataSourceでsetConnectionCachingEnabled(true)をコールすることにより、暗黙的接続キャッシュを有効にします。暗黙的キャッシュを有効にすると、OracleDataSourceへの最初の接続要求により、透過的に接続キャッシュが作成されます。アプリケーション開発者がキャッシュ実装を作成する必要はありません。

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

- 暗黙的接続キャッシュ

- 接続キャッシュの使用

- 接続属性

- 接続キャッシュ・プロパティ

- Connection Cache Manager API

- 高度なトピック

注意:
接続キャッシュの概念は、デフォルト接続を常に使用するサーバー側内部ドライバには関係しません。接続キャッシュは、クライアント側JDBCドライバとサーバー側Thinドライバにのみ関係します。

暗黙的接続キャッシュ

キャッシュがデータソースのアーキテクチャに透過的に統合されるよう、接続キャッシュ・アーキテクチャは再設計されました。

接続キャッシュは、物理接続と論理接続の概念を使用します。物理接続は、データベースによって戻される実際の接続で、論理接続は、物理接続を操作するためにキャッシュが使用するコンテナです。論理接続は、ハンドルとみなすこともできます。キャッシュは、物理接続と同じインタフェースを実装する論理接続を常に戻します。

暗黙的接続キャッシュは、次のものを提供します。

- ドライバからの独立性
JDBC ThinドライバおよびJDBC Oracle Call Interface(OCI)ドライバは、いずれも暗黙的接続キャッシュをサポートします。

- JDBC接続キャッシュへの透過的アクセス
アプリケーションが暗黙的キャッシュを有効にすると、接続の取得に標準OracleDataSource Application Program Interface(API)が使用されます。キャッシュを有効にすると、すべての接続要求が、接続キャッシュから処理されます。

論理接続をクローズするためにアプリケーションがOracleConnection.closeメソッドをコールすると、物理接続がキャッシュに戻されます。

- OracleDataSourceインスタンスごとに1つのキャッシュ
接続キャッシュが有効になると、各キャッシュ対応のOracleDataSourceごとに1つずつキャッシュが関連付けられます。そのデータソースを通じて取得された接続は、使用されたユーザー名とパスワードに関係なく、すべてキャッシュに戻されます。アプリケーションがデータソースからの接続を要求すると、キャッシュは既存の接続を戻すか、または一致する認証情報を使用した新しい接続を作成します。

注意:
キャッシュは、DataSourceインスタンス間で共有されません。キャッシュ対応のDataSourceインスタンスとキャッシュの間には、1対1のマッピングが確立されます。

- 1つのキャッシュでの異なるユーザー名とパスワードの使用
以前のキャッシュ実装と異なり、同じデータソースから取得されたすべての接続が、共通のキャッシュに格納されます。接続が要求したユーザー名とパスワードには関係がありません。

- 複数ユーザーのサポートおよび必須のキャッシュ・プロパティのサポートを含めた、JDBC 3.0接続キャッシュのサポート。

- プロパティに基づいた構成
キャッシュのプロパティは、キャッシュの動作を定義します。サポートされているプロパティは、タイムアウト、キャッシュが保持する接続数などを設定します。これらのプロパティを使用することにより、アプリケーションは放棄された接続を再生および再利用できます。暗黙的接続キャッシュは、すべてのJDBC 3.0接続キャッシュ・プロパティをサポートします。

- OracleConnectionCacheManager
新規OracleConnectionCacheManagerクラスは、接続キャッシュの管理にアプリケーションが使用できる豊富な管理APIを提供しています。仮想マシンごとに、OracleConnectionCacheManagerの別個の1つのインスタンスが存在します。アプリケーションは、単一のOracleConnectionCacheManagerインスタンスによってキャッシュを管理します。

- ユーザー定義の接続属性
暗黙的接続キャッシュは、どの接続がキャッシュから取得されるかを決定するために使用できる、ユーザー定義の接続属性をサポートします。接続属性は、キャッシュ・メカニズムによってでなく、アプリケーションによってセマンティクスが定義されるラベルとみなすことができます。

- コールバック・メカニズム
暗黙的接続キャッシュは、キャッシュへの接続の戻り時、放棄された接続の処理時、および接続が要求されたがキャッシュに存在しない場合のキャッシュの動作を、ユーザーが定義できるメカニズムを提供しています。

- 接続時ロード・バランシング
暗黙的接続キャッシュは、アプリケーションによって接続が最初に作成された時点で、接続時ロード・バランシングを提供します。データベース・リスナーは、接続の作成時点でこの処理を実行するのに最適なOracle Real Application Clustersの複数のインスタンスに接続作成を配布します。

関連項目:
『Oracle Real Application Clusters管理およびデプロイメント・ガイド』

- 実行時接続ロード・バランシング
作業要求の実行時接続ロード・バランシングでは、サービス・メトリックを使用して、最大のパフォーマンスを提供するOracle Real Application Clustersインスタンスに作業要求をルーティングします。サービスに基づいてキャッシュから接続を選択して作業要求を実行すると、スループットが大幅に増加し、スケーラビリティが向上します。

関連項目:
第22章「実行時接続ロード・バランシング」および『Oracle Real Application Clusters管理およびデプロイメント・ガイド』

接続キャッシュの使用

この項では、アプリケーションが暗黙的接続キャッシュを使用する方法を説明します。内容は次のとおりです。

- キャッシュの有効化

- 接続のオープン

- 接続キャッシュ名の設定

- 接続キャッシュ・プロパティの設定

- 接続のクローズ

- 暗黙的接続キャッシュの例

キャッシュの有効化

アプリケーションは、OracleDataSource.setConnectionCachingEnabled(true)をコールすることにより、暗黙的接続キャッシュを有効にします。暗黙的キャッシュを有効にすると、OracleDataSourceクラスへの最初の接続要求により、透過的に接続キャッシュが作成されます。

例21-1に、暗黙的接続キャッシュを使用したサンプル・コードを示します。

例21-1 暗黙的接続キャッシュの使用

// Example to show binding of OracleDataSource to JNDI,
// then using implicit connection cache

import oracle.jdbc.pool.*; // import the pool package

Context ctx = new InitialContext(ht);
OracleDataSource ods = new OracleDataSource();

// Set DataSource properties
ods.setUser("Scott");
ods.setConnectionCachingEnabled(true);    // Turns on caching
ctx.bind("MyDS", ods);
// ...
// Retrieve DataSource from the InitialContext
ods =(OracleDataSource) ctx. lookup("MyDS");

// Transparently create cache and retrieve connection
conn = ods.getConnection();
// ...
conn.close();  // return connection to the cache
// ...
ods.close() // close datasource and clean up the cache

接続のオープン

接続キャッシュを有効にすると、OracleDataSource.getConnectionメソッドを通じて接続を取り出すたびに、キャッシュ内に接続が存在するかどうかがJDBCドライバによって確認されます。

getConnectionメソッドは、キャッシュ内に、指定された条件に一致する未使用の物理接続が存在するかどうかをチェックします。一致するものが見つかった場合、物理接続をラップした状態で論理接続が戻されます。一致する物理接続が見つからなかった場合は、新しい物理接続が作成され、論理接続にラップされて戻されます。

getConnectionには、接続キャッシュを参照しないもの2つと、キャッシュが戻す接続の種類を指定するもの2つの、4つの種類があります。キャッシュ固有でないgetConnectionメソッドは、標準的に動作します。

注意:
暗黙的接続キャッシュを有効にすると、OracleDataSource.getConnectionから戻される接続の状態がリセットされない場合があります。したがって、接続をキャッシュに戻す前に、すべての接続の状態(自動コミット、バッチ・サイズ、プリフェッチ・サイズ、トランザクション・ステータス、トランザクション分離など)をリセットする必要があります。

接続キャッシュ名の設定

OracleDataSourceのConnectionCacheNameプロパティは、Connection Cache Managerが接続キャッシュを管理するために使用するオプションのプロパティです。このプロパティを設定するには、次のメソッドをコールします。

public void synchronized setConnectionCacheName(String cacheName) throws SQLException

このプロパティを設定した場合は、その名前を使用して、キャッシュを有効にするOracleDataSourceがアクセスするキャッシュが一意に識別されます。このプロパティを設定しない場合は、DataSourceName#HexRepresentationOfNumberOfCachesという命名規則を使用して、デフォルトのキャッシュ名が作成されます。

注意:
getConnectionCacheName()メソッドは、setConnectionCachingEnabledメソッドがコールされた後にsetConnectionCacheNameメソッドがコールされた場合にのみ、接続キャッシュの名前を戻します。

接続キャッシュ・プロパティの設定

暗黙的接続キャッシュの動作を詳細に設定するには、setConnectionCachePropertiesメソッドを使用して様々な接続プロパティを設定します。

関連項目:
「接続キャッシュ・プロパティ」

注意:

- キャッシュ固有のプロパティを設定する前に、データソース上でキャッシュを有効にしておく必要があります。そうしない場合、setConnectionCachePropertiesメソッドが機能しません。

- これらのプロパティは接続キャッシュの動作を管理しますが、接続またはキャッシュそのものではなく、データソースで設定されます。

接続のクローズ

アプリケーションは、closeメソッドをコールすることにより、キャッシュに接続を戻します。closeメソッドには、引数のないものと、Connectionオブジェクトを引数にとるものの、2つの変種があります。

注意:

- 接続を確実にキャッシュに戻すために、アプリケーションは接続をクローズする必要があります。

- 暗黙的接続キャッシュを有効にした場合は、接続をキャッシュに戻す前に、すべての接続の状態(自動コミット、バッチ・サイズ、プリフェッチ・サイズ、トランザクション・ステータス、トランザクション分離など)をリセットする必要があります。これによって、キャッシュから取り出した後続の接続の状態が確実にリセットされています。

暗黙的接続キャッシュの例

例21-2に、データソースの作成、キャッシュおよびデータソース・プロパティの設定、接続の取出し、およびキャッシュに戻すための接続のクローズを示します。

例21-2 接続キャッシュの例

import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.naming.*;
import javax.naming.spi.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;

...

// create a DataSource
OracleDataSource ods = new OracleDataSource();

// set cache properties
java.util.Properties prop = new java.util.Properties();
prop.setProperty("MinLimit", "2");
prop.setProperty("MaxLimit", "10");

// set DataSource properties
String url = "jdbc:oracle:oci8:@";
ods.setURL(url);
ods.setUser("hr");
ods.setPassword("hr");
ods.setConnectionCachingEnabled(true); // be sure set to true
ods.setConnectionCacheProperties (prop);
ods.setConnectionCacheName("ImplicitCache01"); // this cache's name

// We need to create a connection to create the cache
Connection conn = ds.getConnection(user, pass);
Statement  stmt  = conn.createStatement();
ResultSet  rset  = stmt.executeQuery("select user from dual");
conn.close();

ods.close();

接続属性

データソースから取得した各接続には、ユーザー定義属性を指定できます。属性は、アプリケーション開発者によって指定される、java.lang.Propertiesの名前と値のペアです。

開発者は、接続属性を使用して、接続を識別するためのセマンティクスを指定できます。たとえば、アプリケーションでconnection_typeという名前の属性を作成し、これに値payrollまたはinventoryを割り当てることができます。

注意:
接続属性のセマンティクスはすべてアプリケーションで定義します。接続キャッシュ自体は、接続属性のキーまたは値に制約を規定しません。

接続属性を取得および設定するメソッドは、OracleConnectionインタフェースに存在します。この項の内容は次のとおりです。

- 接続の取得

- 接続属性の設定

- 戻された接続の属性の確認

- 接続属性の例

接続の取得

初めて取り出す接続には属性がありません。そのため、属性を設定する必要があります。接続の属性を設定した後、getConnectionメソッドの特殊な形式を使用することにより、その接続を属性の指定によって要求できます。

- getConnection(java.util.Properties cachedConnectionAttributes
指定されたcachedConnectionAttributesに一致するデータベース接続を要求します。

関連項目:
接続属性の詳細は、「その他のプロパティ」を参照してください。

- getConnection(java.lang.String user, java.lang.String password, java.util.Properties cachedConnectionAttributes)
指定されたuser、passwordおよびcachedConnectionAttributesに一致するデータベース接続を暗黙的接続キャッシュから要求します。userおよびpasswordについてNULL値が渡された場合、DataSourceのデフォルト値が使用されます。

属性一致規則

connectionAttributesの一致規則には、次の2種類があります。

- 基本
この種類では、キャッシュが検索され、属性に一致する接続が取り出されます。接続検索メカニズムの内容は、次のとおりです。

1. 完全に一致するものが見つかった場合、接続がコール元に戻されます。

2. 完全一致が見つからず、ClosestConnectionMatchデータソース・プロパティが設定されている場合、最も近似のものが戻されます。最も近似の一致の接続は、元の属性の一致が最も多かったものです。最も近似の一致の接続は、元の属性のサブセットに一致しても、元のリストの一部ではない属性を持っていない可能性があります。たとえば、元の属性リストがA、BおよびCの場合、近似の一致はAおよびBを持っていても、Dを持っていない可能性があります。

3. 既存の接続のいずれとも一致しない場合、新しい接続が戻されます。新しい接続は、DataSourceで設定されているユーザー名およびパスワードを使用して作成されます。getConnection(String, String, java.util.Properties)がコールされると、引数として渡されたユーザー名とパスワードを使用して新しい接続がオープンされます。

- 拡張
この種類では、属性が重みに関連付けられます。接続検索メカニズムは基本のconnectionAttributesに基づいた検索と同様ですが、接続がconnectionAttributesにのみ基づいて検索されるのではなく、connectionAttributesのキーに関連付けられた重みも使用して検索されます。これらの重みは、1回のみの操作としてキーに関連付けられ、接続キャッシュ・プロパティAttributeWeightsとしてサポートされます。

接続属性の設定

アプリケーションは、次のメソッドを使用して接続属性を設定します。

applyConnectionAttributes(java.util.Properties connAttr)

connAttrは検証されません。接続属性の適用は累積されます。applyConnectionAttributesをコールするたびに、ユーザーが提供するconnAttr属性は、既存のものに追加されます。

戻された接続の属性の確認

指定された属性の接続がアプリケーションによって要求された際、接続キャッシュ内に一致するものがない可能性があります。このような場合、接続キャッシュは属性を持たない接続を作成し、これを戻します。Connection Cache Managerは属性のセマンティクスを識別できないため、接続キャッシュは要求された属性の接続を作成できません。

注意:
closestConnectionMatchプロパティが設定されている場合、キャッシュ・マネージャは完全一致ではなく近似の一致を検索します。

このため、アプリケーションは戻された接続の属性を必ず確認する必要があります。そのためには、getUnMatchedConnectionAttributesメソッドを使用します。このメソッドは、接続を取得する際に一致しなかったすべての属性のリストを戻します。このメソッドの戻り値がnullの場合、すべての接続属性を設定する必要があることがわかります。

接続属性の例

例21-3に、接続属性の使用方法を示します。

例21-3 接続属性の使用

java.util.Properties connAttr = new java.util.Properties();
connAttr.setProperty("connection_type", "payroll");

// retrieve connection that matches attributes
Connection conn = ds.getConnection(connAttr);
// Check to see which attributes weren't matched
unmatchedProp = ((OracleConnection)conn).getUnMatchedConnectionAttributes();
if ( unmatchedProp != null )
{
// apply attributes to the connection
((OracleConnection)conn).applyConnectionAttributes(connAttr);
}
// verify whether conn contains property after apply attributes
connProp = ((OracleConnection)conn).getConnectionAttributes();
listProperties (connProp);

接続キャッシュ・プロパティ

接続キャッシュ・プロパティは、接続キャッシュの特性を管理します。この項では、サポートされている接続キャッシュ・プロパティについて説明します。内容は次のとおりです。

- 制限プロパティ

- タイムアウト・プロパティ

- その他のプロパティ

- 接続プロパティの例

アプリケーションは、次のいずれかの方法でキャッシュ・プロパティを設定します。

- OracleDataSourceメソッドsetConnectionCachePropertiesを使用して設定する。

- OracleConnectionCacheManagerを使用してキャッシュを作成する際に設定する。

- OracleConnectionCacheManagerを使用してキャッシュを再初期化する際に設定する。

制限プロパティ

これらのプロパティは、キャッシュのサイズを制御します。

InitialLimit

キャッシュの作成時または再初期化時にキャッシュ内に作成される接続数を設定します。このプロパティに0より大きい整数値を設定すると、キャッシュを作成または再初期化した際、指定された数の接続が自動的に作成され、前もってキャッシュを満たします。

デフォルト: 0

MaxLimit

キャッシュが保持できる接続インスタンス数の最大値を設定します。デフォルト値はInteger.MAX_VALUEで、これは、接続キャッシュにより強制される制限がなく、接続の数は、データベースに対して構成されるデータベース・セッションの数によってのみ制限されることを意味します。

デフォルト: Integer.MAX_VALUE(制限なし)

注意:
同時接続数がデータベース・サーバーで構成した最大セッション数を超えると、ORA-00018エラーが発生します。このエラーを回避するには、MaxLimitプロパティの値を設定する必要があります。この値は、データベース・サーバー用に構成したSESSIONSパラメータより小さい値にします。

MaxStatementsLimit

接続がオープン状態にできる文の最大数を設定します。キャッシュでこのプロパティが設定されていると、キャッシュを再初期化するかデータソースをクローズした場合、MaxStatementsLimitを超えた数のすべてのカーソルが自動的にクローズされます。

デフォルト: 0

MinLimit

キャッシュが保持する接続の最小数を設定します。

デフォルト: 0

注意:

- MinLimitプロパティを設定しても、キャッシュが最小数の接続を保持するよう、キャッシュは初期化されません。これを行うには、InitialLimitプロパティを使用してください。

- InitialLimitがMinLimitの値よりも大きい場合は、InitialLimitで指定された接続数をMaxLimitで指定されている値まで大きくすることができます。したがって、InitialLimitはMinLimitに依存していません。

- 接続は、JDBC高速フェイルオーバーのDOWNイベントが処理されているときには、接続プールで設定された最低限の数を下回ることがあります。処理では、プールの影響を受けた接続は削除されます。MinLimitは、接続プールへの要求が増え、接続数がMinLimitの値を超えると適用されます。

タイムアウト・プロパティ

これらのプロパティは、キャッシュ内の要素の存続期間を制御します。

InactivityTimeout

物理接続が接続キャッシュ内にアイドル状態で存続できる最大期間を設定します。アイドルな接続とは、アクティブでなく、論理ハンドルが関連付けられていない接続です。InactivityTimeoutが期限切れになると、基礎となる物理接続がクローズされます。ただし、minLimitが設定されている場合、キャッシュのサイズはそれを下回りません。

デフォルト: 0(タイムアウトなし)

TimeToLiveTimeout

論理接続がオープン状態でいられる最大期間を秒単位で設定します。TimeToLiveTimeoutが期限切れになると、論理接続は無条件にクローズされ、関連付けられた文ハンドルは取り消され、基礎となる物理接続は再利用のためにキャッシュに戻されます。

デフォルト: 0(タイムアウトなし)

関連項目:
「TimeToLiveTimeoutおよびAbandonedConnectionTimeoutのユースケース」

AbandonedConnectionTimeout

接続がクローズされてキャッシュに戻されるまでに、接続が使用されずに維持される最大期間を設定します。SQLデータベース・アクティビティがない場合、接続は使用されていないとみなされます。

AbandonedConnectionTimeoutが設定されると、JDBCによって各論理接続のSQLデータベース・アクティビティが監視されます。たとえば、stmt.executeが接続に対してコールされると、この接続がアクティブであることを伝えるハートビートが登録されます。ハートビートは、データベースの実行ごとに設定されます。指定された期間、接続が非アクティブであると、基礎となる接続は再生され、再利用のためにキャッシュに戻されます。

デフォルト: 0(タイムアウトなし)

関連項目:
「TimeToLiveTimeoutおよびAbandonedConnectionTimeoutのユースケース」

PropertyCheckInterval

Connection Cache Managerがすべての指定されたキャッシュ・プロパティを確認および強制する時間隔を設定します。PropertyCheckIntervalは秒単位で設定されます。

デフォルト: 900秒

関連項目:
『Oracle Database Net Services管理者ガイド』

その他のプロパティ

これらのプロパティは、様々なキャッシュの動作を制御します。

AttributeWeights

AttributeWeightsは、接続に設定された各属性の重みを設定します。

関連項目:
「AttributeWeights」

ClosestConnectionMatch

ClosestConnectionMatchは、指定された接続属性と最も近似した接続を接続キャッシュによって取り出します。

関連項目:
「ClosestConnectionMatch」

ConnectionWaitTimeout

接続が要求されたが、アクティブな接続がすでにMaxLimit本ある場合のキャッシュ動作を指定します。ConnectionWaitTimeoutがゼロの場合、各接続要求は0秒待機します。つまり、null接続が即座に戻されます。ConnectionWaitTimeoutがゼロより大きい場合、各接続要求は、指定された秒数、または接続がキャッシュに戻されるまでの間、待機します。接続がキャッシュに戻されないままタイムアウトした場合、接続要求はnullを戻します。

デフォルト: ゼロ

LowerThresholdLimit

キャッシュの最低のしきい値を設定します。デフォルトは、接続キャッシュのMaxLimitの20%です。このプロパティは、releaseConnection()キャッシュのコールバック・メソッドが使用されている場合は必ず使用されます。

ValidateConnection

ValidateConnectionにtrueを設定すると、接続キャッシュが取り出した接続は、すべて、基礎となるデータベースに対して検証されます。有効な接続が取り出せない場合は、例外が発生します。

デフォルト: false

注意:
Oracle Database 11gリリース1(11.1)以上では、接続キャッシュの動作が変更されています。ValidateConnectionプロパティとデータベースのCONNECT_TIMEリソース制限の両方が有効である場合、接続キャッシュは、例外を発行せずに、CONNECT_TIME制限に設定されている値を超える接続を戻します。次回この接続で文が実行されると、かわりに例外が発行されます。
ValidateConnectionプロパティを有効にしているときは、CONNECT_TIME制限を設定しないことをお薦めします。

接続プロパティの例

例21-4に、アプリケーションが接続プロパティを使用する方法を示します。

例21-4 接続プロパティの使用

import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.naming.*;
import javax.naming.spi.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
...
OracleDataSource ds =  (OracleDataSource) ctx.lookup("...");
java.util.Properties prop = new java.util.Properties ();
prop.setProperty("MinLimit", "5");     // the cache size is 5 at least
prop.setProperty("MaxLimit", "25");
prop.setProperty("InitialLimit", "3"); // create 3 connections at startup
prop.setProperty("InactivityTimeout", "1800");    //  seconds
prop.setProperty("AbandonedConnectionTimeout", "900");  //  seconds
prop.setProperty("MaxStatementsLimit", "10");
prop.setProperty("PropertyCheckInterval", "60"); // seconds

ds.setConnectionCacheProperties (prop);  // set properties
Connection conn = ds.getConnection();
conn.dosomework();
java.util.Properties propList=ds.getConnectionCacheProperties();  // retrieve

Connection Cache Manager API

OracleConnectionCacheManagerでは、使用可能な接続キャッシュを中間層によって管理するための管理APIを提供しています。この項では、Connection Cache Managerの使用例を示します。

ConnectionCacheManagerの使用例

例21-5に、OracleConnectionCacheManagerインタフェースを示します。

例21-5 Connection Cache Managerの例

import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.naming.*;
import javax.naming.spi.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
...
// Get singleton ConnectionCacheManager instance
OracleConnectionCacheManager occm =
OracleConnectionCacheManager.getConnectionCacheManagerInstance();
String cacheName = "foo";  // Look for a specific cache
// Use Cache Manager to check # of available connections
// and active connections
System.out.println(occm.getNumberOfAvailableConnections(cacheName)
" connections are available in cache " + cacheName);

System.out.println(occm.getNumberOfActiveConnections(cacheName)
+ " connections are active");
// Refresh all connections in cache
occm.refreshCache(cacheName,
OracleConnectionCacheManager.REFRESH_ALL_CONNECTIONS);
// Reinitialize cache, closing all connections
java.util.Properties newProp = new java.util.Properties();
newProp.setProperty("MaxLimit", "50");
occm.reinitializeCache(cacheName, newProp);

高度なトピック

この項では、暗黙的接続キャッシュの理解や使用にとって必須ではないが、上級者には役立つキャッシュ機能について説明します。この項の内容は次のとおりです。

- 属性の重みと接続の一致

- 接続キャッシュのコールバック

属性の重みと接続の一致

getConnection要求に対し、接続キャッシュ内の適切な接続を指定するために開発者が使用できる接続キャッシュ・プロパティは2つあります。ClosestConnectionMatchプロパティにtrueを設定すると、Connection Cache Managerは、指定された属性の一部のみ一致する接続を戻します。

attributeWeightsを指定しない場合、一致する属性が最も多い接続がConnection Cache Managerによって戻されます。attributeWeightsを指定すると、属性を一致する際にマネージャによって使用される優先順位を制御できます。

ClosestConnectionMatch

ClosestConnectionMatchにtrueを設定すると、指定された接続属性と最も近似した接続が接続キャッシュによって取り出されます。これとAttributeWeightsを組み合せることにより、最も近似した一致を指定できます。

デフォルト: false

AttributeWeights

各connectionAttributeの重みを設定します。このプロパティは、一致を検索する際、どの属性の優先順位が最も高いかを決定するために、ClosestConnectionMatchにtrueが設定されている場合に使用されます。重みが高い属性は、重みが低い属性よりも、一致を決定する際に重要視されます。

AttributeWeightsには、キー/値ペアを表すStringのセットが含まれています。各キー/値ペアのセットには、ユーザーが接続を要求する各connectionAttributeの重みを設定します。各Stringは、java.util.Properties.Store(OutputStream, String)メソッドで記述される形式であるため、java.util.Properties.load(InputStream)メソッドで読み取ることができます。KeyはconnectionAttribute、Valueは重みです。重みは0より大きい整数値の必要があります。デフォルトの重みは1です。

たとえば、TRANSACTION_ISOLATIONに10の重み、ROLEに5の重みを割り当てます。ClosestConnectionMatchをtrueに設定し、connectionAttributeに基づいてキャッシュに接続が要求されると、一致するTRANSACTION_ISOLATIONを持つ接続は、一致するROLEを持つ接続よりも優先されます。

デフォルト: AttributeWeightsなし

接続キャッシュのコールバック

暗黙的接続キャッシュを使用することにより、接続キャッシュがコールするコールバックをアプリケーションによって指定できます。コールバック・メソッドは、OracleConnectionCacheCallbackインタフェースによってサポートされます。このコールバック・メカニズムは、特定の接続に対するアプリケーションの認識を利用し、放棄された接続の処理や、キャッシュが空の場合のデフォルトの動作を補完する際に役立ちます。

OracleConnectionCacheCallbackは、ユーザーが実装し、OracleConnectionに登録する必要のあるインタフェースです。登録APIは次のとおりです。

public void
registerConnectionCacheCallback(
OracleConnectionCacheCallback cbk, Object usrObj,  int cbkflag);

このインタフェースで、cbkはOracleConnectionCacheCallbackインタフェースのユーザーによる実装です。usrObjパラメータには、ユーザーが提供する任意のパラメータが含まれます。コールバック・メソッドがコールされると、このユーザー・オブジェクトは変更されずに戻されます。cbkflagパラメータは、コールするコールバック・メソッドを指定します。次の値のうち1つを設定する必要があります。

- OracleConnection.ABANDONED_CONNECTION_CALLBACK

- OracleConnection.RELEASE_CONNECTION_CALLBACK

- OracleConnection.ALL_CALLBACKS

ALL_CALLBACKSが設定されると、すべての接続キャッシュのコールバック・メソッドがコールされます。たとえば、次のようになります。

// register callback, to invoke all callback methods
((OracleConnection)conn).registerConnectionCacheCallback( new UserConnectionCacheCallback(),
new SomeUserObject(),
OracleConnection.ALL_CALLBACKS);

アプリケーションは、OracleConnectionにConnectionCacheCallbackを登録できます。コールバックが登録されると、接続キャッシュは接続を再生する前に、コールバックのhandleAbandonedConnectionメソッドをコールします。コールバックがtrueを戻すと、接続は再生されます。コールバックがfalseを戻すと、接続はアクティブ状態のままになります。

UserConnectionCacheCallbackインタフェースは、releaseConnectionおよびhandleAbandonedConnectionという、ユーザーが実装する2つのコールバック・メソッドをサポートしています。

TimeToLiveTimeoutおよびAbandonedConnectionTimeoutのユースケース

次に、暗黙的接続キャッシュで使用される、TimeToLiveTimeoutとAbandonedConnectionTimeoutのタイムアウト・メカニズムのユースケースについて説明します。これらのタイムアウト・メカニズムは、接続キャッシュから取り出された論理接続に適用できます。

- 接続が完全にステートレスであるとアプリケーションでみなされる場合
接続がステートレスである場合は、どちらかのタイムアウト・メカニズムを使用できます。タイムアウトが期限切れとなった接続は、再利用のために接続キャッシュに戻されます。これらの接続には、関連付けられたセッション状態がないため、再利用の対象として有効です。

- 各接続の状態がアプリケーションで維持されるが、接続キャッシュに戻された接続をステートレスにできるクリーン・アップ・ルーチンがアプリケーションにある場合
この場合、TimeToLiveTimeoutは使用できません。接続キャッシュの側で、接続が必ず再使用可能な状態でキャッシュに戻されるように保証する手段はありません。ただし、このシナリオでは、その接続上でOracleConnectionCacheCallbackが登録されている場合のみ、AbandonedConnectionTimeoutを使用できます。handleAbandonedConnectionコールバック・メソッドはアプリケーションにより実装され、必要なクリーン・アップが完了していることを保証します。タイムアウト処理がこのコールバック・メソッドを起動すると、接続はクローズされます。この接続をコールバック・メソッドによってクローズすると、接続は再使用できる状態で接続キャッシュに戻されます。

注意:
handleAbandonedConnectionメソッドをコールした後に接続をクローズしないでください。接続が無効な状態になる可能性があります。JDBCは、接続が無効な状態にある場合でも、接続を回収する方法を内部的に認識しています。

関連項目:
「接続キャッシュのコールバック」

- 各接続の状態がアプリケーションで維持されるが、接続は管理されず、他のアプリケーションやユーザーによる再利用のために状態をクリーン・アップできない場合
どちらのタイムアウト・メカニズムも、使用はお薦めしません。

22 実行時接続ロード・バランシング

Oracle Database 11gには、実行時接続ロード・バランシング機能があります。この章の内容は次のとおりです。

- 実行時接続ロード・バランシングの概要

- 実行時接続ロード・バランシングの有効化

注意:
Oracle Database 11gリリース2 (11.2)から、この機能は非推奨となり、Universal Connection Pool (UCP) for JDBCがこれに置き換わりました。新しいアーキテクチャは、以前より強力でパフォーマンスも向上しているため、こちらを使用することをお薦めします。詳細は、次のリンクを参照してください。

http://www.oracle.com/technology/tech/java/sqlj_jdbc/index.html

実行時接続ロード・バランシングの概要

Oracle Real Application Clusters環境では、接続は関連サービスを提供するインスタンスに属しています。すべてのインスタンスが等しく実行され、接続がキャッシュからランダムに取り出されるのが最も理想的です。しかし、あるインスタンスのパフォーマンスが他のインスタンスを上回る場合、接続をランダムに選択すると効率が悪くなります。実行時接続ロード・バランシング機能を使用すると、最適なパフォーマンスを提供するインスタンスに作業要求がルーティングされるため、作業を再配置する必要が最小限になります。

図22-1は、実行時接続ロード・バランシングを示しています。実行時接続ロード・バランシングを暗黙的接続キャッシュで有効にすると、次の処理が実行されます。

1. クライアントは、DataSourceオブジェクトのgetConnectionメソッドをコールして、接続キャッシュから接続を要求します。

2. 実行時接続ロード・バランシング・メカニズムによって、接続キャッシュから最適なインスタンスに属する接続が選択されます。図22-1の例では、インスタンス1またはインスタンス2が該当します。

3. 最適な応答時間でクライアントが接続を受け取り、作業要求が処理されます。

図22-1 実行時接続ロード・バランシング

「図22-1 実行時接続ロード・バランシング」の説明

ロード・バランシング・アドバイザに基づく接続取出しは自動的に行われます。接続の要求は、ロード・バランシング・アドバイザによって決定されたサービス目標に基づいて接続を選択することで処理されます。このサービス目標によって、接続が最高のサービス品質を提供するかどうか(つまり1つのトランザクションがどの程度効率的に完了するか)、あるいは最適なスループットを提供するかどうか(つまりジョブ全体または長時間実行される問合せがどの程度効率的に完了するか)が決まります。ロード・バランシング・アドバイザは、Oracle Real Application Clustersによってイベントが送信されているかぎり、接続キャッシュによって使用されます。イベントの着信が停止すると、接続キャッシュはキャッシュからのランダムな接続取出しに戻ります。

実行時接続ロード・バランシングはOracle Notification Service(ONS)インフラストラクチャに依存します。実行時接続ロード・バランシングでは、高速接続フェイルオーバー処理で使用するのと同じバンド外ONSイベント・メカニズムを使用します。したがって、高速接続フェイルオーバーが有効になると、実行時接続ロード・バランシングもデフォルトで有効になります。実行時接続ロード・バランシングが機能するためにONSの追加設定や構成は必要ありません。

関連項目:
「高速接続フェイルオーバーの使用」

実行時接続ロード・バランシングの有効化

実行時接続ロード・バランシングを有効にして使用するには、次の方法でOracle Real Application Clustersデータベースを構成する必要があります。

- サービス目標は、次のいずれかに設定する必要があります。

- DBMS_SERVICE.SERVICE_TIME

- DBMS_SERVICE.THROUGHPUT

- 接続バランシング目標はSHORTに設定する必要があります。

これらの目標は、dbms_service.create_serviceまたはdbms_service.modify_serviceをコールする場合、設定する必要があります。サービス目標はgoalパラメータを使用して、接続バランシング目標はclb_goalパラメータを使用して設定できます。

注意:
接続バランシング目標は、LONGに設定することができます。ただし、これはクローズされたワークロードに対して、つまり完了した作業の割合と新しく始める作業の割合が等しいときに、最も有効です。

関連項目:
『Oracle Real Application Clusters管理およびデプロイメント・ガイド』

23 パフォーマンス拡張機能

この章では、Java Database Connectivity(JDBC)標準に対するOracleパフォーマンス拡張機能について説明します。

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

- バッチ更新

- その他のOracleパフォーマンス拡張機能

バッチ更新

複数のUPDATE文、DELETE文またはINSERT文を単一のバッチにグループ化して、バッチ全体を一度にデータベースに送信して処理することによって、データベースへのラウンドトリップの回数を減らし、それによってアプリケーションのパフォーマンスを向上させることができます。これは、バッチ更新(update batching)と呼ばれます。

注意:
JDBC 2.0仕様では、これをバッチ更新(batch updates)と呼びます。

これは、特にプリコンパイルされたSQL文で、同じ文をバインド変数を変えて繰り返し使用する場合に効果的です。

Oracle JDBCでは、2つの異なるバッチ更新のモデルがサポートされています。

- 標準モデル。JDBC 2.0仕様を実装します。これは、標準バッチ更新と呼ばれます。

- Oracle固有モデル。JDBC 2.0仕様から独立しています。これは、Oracleバッチ更新と呼ばれます。

注意:
これらのモデルは混在させることができません。単一アプリケーションで、どちらのモデルを使用してもかまいませんが、両方は使用できません。これらを混在させると、Oracle JDBCドライバで例外が発生します。

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

- バッチ更新モデルの概要

- Oracleバッチ更新

- 標準バッチ更新

- 早期バッチ・フラッシュ

バッチ更新モデルの概要

この項では、標準バッチ更新とOracleバッチ更新用にサポートされている、一般的なモデルと型を比較します。

Oracleモデルと標準モデル

Oracleバッチ更新では、通常は暗黙的なバッチ処理となるバッチ値を使用します。バッチ値とは、データベースへのトリップごとにバッチに追加する操作の数です。この値まで操作がバッチに追加されると、バッチが処理されます。次のことに注意してください。

- 接続オブジェクトにデフォルト・バッチ値を設定できます。このバッチ値は、その接続で実行されるプリコンパイルされたSQL文すべてに適用されます。

- プリコンパイルされたSQL文オブジェクトには、個別に文バッチ値を設定できます。この値は、接続バッチ値より優先します。

- 接続バッチ値と文バッチ値の両方を無視して、いつでも明示的にバッチを処理できます。

標準のバッチ更新は、手動の明示的なモデルです。バッチ値は設定されていません。手動で操作をバッチに追加し、明示的にバッチ処理のタイミングを選択します。

注意:

- 可能なかぎりJDBC標準機能の使用をお薦めします。この推奨は、バッチ処理の更新にも当てはまります。Oracleバッチ更新は、主として下位互換性用に維持されています。

- 標準バッチ更新とOracleバッチ更新の両方とも、バッチ・サイズを50から100の一般的な範囲に保つことをお薦めします。これは、ドライバでサポートするバッチが大きくなっても、その結果メモリー・フットプリントが大きくなり、パフォーマンスがそれに応じて向上しないためです。非常に大きなバッチは、通常、小さなバッチと比べて、パフォーマンスが低下します。

サポートされている文の型

Oracleによる実装のとおり、バッチ更新は、同じ文をバインド変数を変えて繰り返し使用する場合に、プリコンパイルされたSQL文で使用するように用意されています。次のことに注意してください。

- Oracleバッチ更新でサポートされるのは、プリコンパイルされたSQL文オブジェクトのみです。コール可能文では、接続デフォルト・バッチ値と文バッチ値の両方が値1にオーバーライドされます。Oracleの一般的な文では、文バッチ値はなく、接続デフォルト・バッチ値は値1にオーバーライドされます。

- JDBC 2.0標準に準拠するために、標準バッチ更新のOracle実装では、プリコンパイルされたSQL文と同じように、OUTパラメータなしのコール可能文および一般的な文もサポートされています。標準バッチ更新は、Oracle JDBCアプリケーションに簡単に移行できます。

- バッチできるのは、UPDATE、INSERTまたはDELETE操作のみです。結果セットを戻そうとする操作を含むバッチを処理すると、例外が発生します。

注意:
標準バッチ更新のOracle実装では、一般的な文およびコール可能文の実際のバッチ処理は実装されていません。Oracle JDBCはStatementおよびCallableStatementオブジェクトに対する標準バッチ処理構文の使用をサポートしますが、パフォーマンスが向上するのはPreparedStatementオブジェクトの場合のみです。

Oracleバッチ更新

Oracleバッチ更新によって、バッチ値がプリコンパイルされたSQL文オブジェクトに関連付けられます。Oracleバッチ更新を使用すると、JDBCドライバはexecuteUpdateメソッドがコールされるたびにプリコンパイルされたSQL文を実行するのではなく、蓄積された処理要求のバッチに文を追加します。バッチ値に達すると、ドライバはすべての操作をデータベースに渡して一度に処理します。たとえば、バッチ値が10の場合、10の操作がバッチに蓄積されるたびにデータベースに送信され、1回のラウンドトリップで処理されます。

OracleConnectionクラスのメソッドを使用すると、Oracle接続全体に対するデフォルト・バッチ値を設定できます。このバッチ値は、接続内のすべてのプリコンパイルされたOracle SQL文に適用されます。任意の特定のOracleプリコンパイルされたSQL文に対して、OraclePreparedStatementクラスにおけるメソッドを使用して文バッチ値を設定できます。この値は、接続バッチ値より優先されます。保留中のバッチの手動処理を選択することで、両方のバッチ値より優先させることもできます。

注意:

- 標準バッチ更新とOracleバッチ更新を同じアプリケーションに混在させることはできません。これらを混在させると、JDBCドライバで例外が発生します。

- どちらかのバッチ更新モデルを使用する場合、自動コミット・モードは無効になります。バッチの処理中にエラーが発生した場合、エラーの前に正常に実行された操作をコミットするかロールバックするかを選択できます。

Oracleバッチ更新の特性と制限事項

Oracleバッチ更新に関する、次の制限事項と実装の詳細に注意してください。

- デフォルトでは、文バッチ値はなく、接続バッチ値は1です。

- バッチ値は、5から30にすると最も効率的です。非常に高い値を設定すると、逆効果になります。特定のアプリケーションでの有効性を検証するために、様々な値を試すことをお薦めします。

- バッチ値が有効かどうかにかかわらず、Oracle PreparedStatementのバインド変数がストリーム型である場合、Oracle JDBCドライバによりバッチ値は1に設定され、処理待ちの要求はすべてデータベースに送信され、処理されます。

- Oracle JDBCドライバは、次の場合に、Oracle PreparedStatementのsendBatchメソッドを自動的に実行します。

- 接続が、commitメソッドのコールまたは自動コミット・モードの結果として、COMMIT要求を受信した場合。

- 文が、close要求を受信した場合。

- 接続が、close要求を受信した場合。

注意:
接続COMMIT要求、文クローズまたは接続クローズは、Oracleバッチ更新を使用する場合のみ、保留バッチに影響を与えます。ただし、標準バッチ更新を使用する場合は、保留バッチに影響を与えません。

- sendBatchがコールされる前に接続がROLLBACK要求を受信した場合は、保留バッチ処理が削除されません。削除するには、clearBatchを明示的にコールする必要があります。

接続バッチ値の設定

Oracle接続では、任意のOracle PreparedStatementにデフォルト・バッチ値を指定できます。この値を指定するには、OracleConnectionオブジェクトのsetDefaultExecuteBatchメソッドを使用します。たとえば、次のコードにより、conn接続オブジェクトに関連付けられているすべてのプリコンパイルされたSQL文に対して、デフォルト・バッチ値が20に設定されます。

((OracleConnection)conn).setDefaultExecuteBatch(20);

このメソッドにより、その接続のプリコンパイルされたSQL文すべてに対してデフォルト・バッチ値が設定されますが、Oracle PreparedStatementで個別にoracle.jdbc.OraclePreparedStatementインタフェースのsetExecuteBatchをコールすると、その設定値をオーバーライドできます。

接続バッチ値は、このバッチ値がセットされた後で作成された文オブジェクトに適用されます。

Java Propertiesオブジェクトを使用して接続を確立した場合、setDefaultExecuteBatchメソッドをコールするかわりに、defaultBatchValue Javaプロパティを設定することもできます。

文バッチ値の設定

特定のOracle PreparedStatementに文バッチ値を設定するには、次の手順を使用します。これにより、文を処理する接続のOracleConnectionインスタンスのsetDefaultExecuteBatchメソッドを使用して設定した接続バッチ値はすべて、オーバーライドされます。

1. 次のように、プリコンパイルされたSQL文を記述し、第1行の入力値を指定します。

PreparedStatement ps = conn.prepareStatement
("INSERT INTO dept VALUES (?,?,?)");
ps.setInt (1,12);
ps.setString (2,"Oracle");
ps.setString (3,"USA");

2. プリコンパイルされたSQL文をOraclePreparedStatementにキャストし、setExecuteBatchメソッドを適用します。この例では、文のバッチ・サイズは2に設定されます。

((OraclePreparedStatement)ps).setExecuteBatch(2);

必要に応じて、プログラムの任意の場所に、次のようにgetExecuteBatchメソッドを挿入すると、文のデフォルト・バッチ値を確認できます。

System.out.println (" Statement Execute Batch Value " +
((OraclePreparedStatement)ps).getExecuteBatch());

3. この時点で更新を実行するコールをデータベースに送信しても、データはデータベースに送信されず、0(ゼロ)が戻されます。

// No data is sent to the database by this call to executeUpdate
System.out.println ("Number of rows updated so far: "
+ ps.executeUpdate ());

4. 第2行の入力値の集合および更新の実行を入力すると、executeUpdateのバッチ・コール回数がバッチ値2と等しくなります。データはデータベースに送信され、1回のラウンドトリップで2つの行が挿入されます。

ps.setInt (1, 11);
ps.setString (2, "Applications");
ps.setString (3, "Indonesia");

int rows = ps.executeUpdate ();
System.out.println ("Number of rows updated now: " + rows);

ps.close ();

バッチ値のチェック

Oracle接続インスタンスの全体的な接続バッチ値をチェックするには、OracleConnectionクラスのgetDefaultExecuteBatchメソッドを使用します。

Integer batch_val = ((OracleConnection)conn).getDefaultExecuteBatch();

Oracle PreparedStatementの特定の文バッチ値をチェックするには、OraclePreparedStatementクラスのgetExecuteBatchメソッドを使用します。

Integer batch_val = ((OraclePreparedStatement)ps).getExecuteBatch();

注意:
文バッチ値が設定されていない場合、getExecuteBatchは接続バッチ値を戻します。

バッチ値のオーバーライド

有効なバッチ値に達する前に、蓄積された操作を処理するには、OraclePreparedStatementオブジェクトのsendBatchメソッドを使用します。

この例では、接続バッチ値を20に設定します。これにより、接続に関連付けられているすべてのプリコンパイルされたSQL文オブジェクトのデフォルト・バッチ値は、20に設定されます。次のように、接続をOracleConnectionにキャストし、接続にsetDefaultExecuteBatchメソッドを適用します。

((OracleConnection)conn).setDefaultExecuteBatch (20);

次のように、バッチ値をオーバーライドします。

1. 次のように、プリコンパイルされたSQL文を記述し、第1行の入力値を指定して、この文を処理します。

PreparedStatement ps =
conn.prepareStatement ("insert into dept values (?, ?, ?)");

ps.setInt (1, 32);
ps.setString (2, "Oracle");
ps.setString (3, "USA");

System.out.println (ps.executeUpdate ());

この時点では、バッチは処理されません。ps.executeUpdateメソッドにより0が戻されます。

2. 2番目の操作の入力値の集合を入力し、もう一度executeUpdateをコールしても、データはデータベースに送信されません。文に対して有効なバッチ値は、接続のバッチ値である20です。

ps.setInt (1, 33);
ps.setString (2, "Applications");
ps.setString (3, "Indonesia");

// this batch is still not executed at this point
int rows = ps.executeUpdate ();

System.out.println ("Number of rows updated before calling sendBatch: "
+ rows);

println文のrowsの値が0である点に注意してください。

3. この時点でsendBatchを適用すると、これまでにバッチされていた2つの操作が、1回のラウンドトリップでデータベースに送信されます。sendBatchメソッドからは、更新された行の合計数も戻されます。sendBatchのプロパティをprintlnで使用すると、更新された行数が出力されます。

// Execution of both previously batched executes will happen
// at this point. The number of rows updated will be
// returned by sendBatch.
rows = ((OraclePreparedStatement)ps).sendBatch ();

System.out.println ("Number of rows updated by calling sendBatch: "
+ rows);
ps.close ();

Oracleバッチ処理での変更のコミット

バッチを処理した後、変更をコミットする必要があります。自動コミットは使用禁止(推奨)にしてあるものとします。

Oracleバッチ処理で接続オブジェクトのcommitをコールすると、処理されたバッチの操作がコミットされるのみでなく、暗黙的なsendBatchコールが発行され、保留バッチがすべて処理されます。このように、commitによって、バッチに追加されたすべての操作による変更が効率的にコミットされます。

Oracleバッチ処理による更新件数

バッチを使用しない場合、OraclePreparedStatementオブジェクトのexecuteUpdateメソッドからは、操作の影響を受けたデータベース行の数が戻されます。

Oracleバッチ処理を使用する場合、このメソッドからは、次のように、メソッドが起動されたときに影響を受けた行の数が返されます。

- executeUpdateのコールによって操作がバッチに追加される場合、値0(ゼロ)が戻されます。その時点では、データベースには何も書き込まれません。

- executeUpdateのコールによってバッチ値に達し、バッチが処理される場合、バッチに含まれるすべての操作によって影響を受ける行の合計数が戻されます。

同様に、OraclePreparedStatementオブジェクトのsendBatchメソッドからは、バッチに含まれるすべての操作によって影響を受ける行の合計数が戻されます。

例23-1は、Oracleバッチ更新の使用方法を示しています。

例23-1 Oracleバッチ更新

次の例では、Oracleバッチ更新機能の使用方法を示します。この例では、oracle.driver.*インタフェースがインポート済であることを前提にしています。

...
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci);
ods.setUser("scott");
ods.setPassword("tiger");

Connection conn = ods.getConnection();
conn.setAutoCommit(false);

PreparedStatement ps =
conn.prepareStatement("insert into dept values (?, ?, ?)");

//Change batch size for this statement to 3
((OraclePreparedStatement)ps).setExecuteBatch (3);

ps.setInt(1, 23);
ps.setString(2, "Sales");
ps.setString(3, "USA");
ps.executeUpdate(); //JDBC queues this for later execution

ps.setInt(1, 24);
ps.setString(2, "Blue Sky");
ps.setString(3, "Montana");
ps.executeUpdate(); //JDBC queues this for later execution

ps.setInt(1, 25);
ps.setString(2, "Applications");
ps.setString(3, "India");
ps.executeUpdate(); //The queue size equals the batch value of 3
//JDBC sends the requests to the database

ps.setInt(1, 26);
ps.setString(2, "HR");
ps.setString(3, "Mongolia");
ps.executeUpdate(); //JDBC queues this for later execution

((OraclePreparedStatement)ps).sendBatch(); // JDBC sends the queued request
conn.commit();

ps.close();
...

注意:
バッチによって遅延した更新は、他の問合せの結果に影響を与えることがあります。次の例では、バッチにより最初の問合せが遅延した場合は、次の問合せから予期しない結果が戻されます。

UPDATE emp SET name = "Sue" WHERE name = "Bob";
SELECT name FROM emp WHERE name = "Sue";

Oracleバッチ更新におけるエラー・レポート

executeBatchがコールされたとき、バッチ処理された操作のうち1つでも失敗したり、結果セットを戻そうとしたりすると、処理は停止し、java.sql.BatchUpdateExceptionが生成されます。

例外が発生した場合は、BatchUpdateExceptionオブジェクトのgetUpdateCountsメソッドをコールすると、更新件数を取得できます。このメソッドからは、executeBatchメソッドと同じように、更新件数のint配列が戻されます。

Oracle Database 11gリリース2(11.2)の場合、戻される整数配列にはStatement.EXECUTE_FAILEDエントリがn個(nはバッチのサイズ)含まれます。ただし、これは、バッチ内でエラーが発生した箇所を示しているわけではありません。この場合は、トランザクションをロールバックするしか有効な手段がありません。

Oracle Database 11gリリース2(11.2)の場合、戻される整数配列にはStatement.SUCCESS_NO_INFOエントリがn個(nはバッチ内で正常に実行された要素の数)含まれます。

注意:
バッチの実行は常に、バッチ内でエラーが最初に生成された要素で停止します。

標準バッチ更新

JDBC標準バッチ更新は、Oracleバッチ更新モデルと異なり、addBatchメソッドを使用して明示的に文をバッチに追加し、executeBatchメソッドを使用して明示的にバッチを処理します。Oracleモデルでは、バッチ処理を行わない場合と同様にexecuteUpdateをコールしますが、操作をバッチに追加するか、バッチ全体を処理するかは、通常、あらかじめ定義されているバッチ値に達したかどうかによって、暗黙的に判断されます。

注意:

- 標準バッチ更新とOracleバッチ更新を同じアプリケーションに混在させることはできません。これらを混在させると、Oracle JDBCドライバで例外が発生します。

- どちらかのバッチ更新モデルを使用する場合、自動コミット・モードは無効化します。バッチの処理中にエラーが発生した場合、エラーの前に正常に実行された操作をコミットするかロールバックするかを選択できます。

標準バッチ処理のOracle実装の制限事項

この項では、標準バッチ更新のOracle実装に関する、制限事項と実装の詳細を説明します。

Oracle JDBCアプリケーションでバッチ更新を使用すると、バインド変数の設定を変えてプリコンパイルされたSQL文を繰り返し処理できます。

標準バッチ更新のOracle実装では、一般的な文およびコール可能文の実際のバッチ処理は実装されていません。Oracle JDBCはStatementおよびCallableStatementオブジェクトに対する標準バッチ処理の使用をサポートしますが、パフォーマンスは向上しません。

バッチに対する操作の追加

いかなる文オブジェクトも、最初に作成されたとき、その文バッチは空です。文バッチに操作を追加するには、標準のaddBatchメソッドを使用します。このメソッドは標準のjava.sql.Statementインタフェース、PreparedStatementインタフェースおよびCallableStatementインタフェースで指定され、それぞれ、oracle.jdbc.OracleStatementインタフェース、OraclePreparedStatementインタフェースおよびOracleCallableStatementインタフェースで実装されます。

Statementオブジェクトの場合、addBatchメソッドは、入力としてSQL操作のJava Stringを取ります。たとえば、次のようになります。

...
Statement stmt = conn.createStatement();

stmt.addBatch("INSERT INTO emp VALUES(1000, 'Joe Jones')");
stmt.addBatch("INSERT INTO dept VALUES(260, 'Sales')");
stmt.addBatch("INSERT INTO emp_dept VALUES(1000, 260)");
...

この時点で、バッチには3つの操作が入っています。

注意:
ただし、標準バッチ更新のOracle実装では、一般的な文をバッチ処理してもパフォーマンスは向上しません。

プリコンパイルされたSQL文の場合、バッチ更新は、異なる組合せのバインド・パラメータを使用して、同じ文を複数回実行するために使用されます。PreparedStatementオブジェクトまたはOraclePreparedStatementオブジェクトの場合、addBatchメソッドは、入力を取りません。適切なsetXXXメソッドによって最後に設定されたバインド・パラメータを使用して、操作をバッチに追加するだけです。CallableStatementオブジェクトやOracleCallableStatementオブジェクトの場合も同様です。ただし、標準更新バッチのOracle実装では、コール可能文をバッチ処理してもパフォーマンスはおそらく向上しないことに注意してください。

たとえば、次のようになります。

...
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");

pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();

pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
...

この時点で、バッチには2つの操作が入っています。

1つのバッチは単一のPreparedStatementオブジェクトに関連付けられるので、バッチ処理できるのは、この例のような単一のプリコンパイルされたSQL文の繰返し実行のみです。

バッチの処理

現在の操作バッチを処理するには、文オブジェクトのexecuteBatchメソッドを使用します。このメソッドは標準のStatementインタフェースで指定されます。これは標準PreparedStatementインタフェースとCallableStatementインタフェースで拡張されています。

次の例では、前の例で示したプリコンパイルされたSQL文のaddBatchコールを繰り返した後、バッチを処理します。

...
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");

pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();

pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();

int[] updateCounts = pstmt.executeBatch();
...

Oracle Database 11gリリース1(11.1)以上では、executeBatchメソッドが改善され、バッチ実行中にエラーが発生した場合、発生するBatchUpdateExecution例外にバッチ内でのエラーの位置が含まれるようになりました。BatchUpdateExecution.getUpdateCountsメソッドは、このエラーが発生する前に正常に実行された更新の更新回数を含むintの配列を戻します。このため、エラーがバッチの5番目の要素で発生した場合に戻される配列のサイズは4で、それぞれの値がStatement.SUCCESS_NO_INFOとなります。

標準バッチ処理のOracle実装による変更のコミット

バッチを処理した後、変更をコミットする必要があります。自動コミットは使用禁止(推奨)にしてあるものとします。

commitをコールすると、処理済の文バッチの場合、バッチ処理された操作とされなかった操作がコミットされますが、標準バッチのOracle実装では、未処理の保留文バッチには影響がありません。

バッチの消去

現在の操作バッチを処理しないで消去するには、文オブジェクトのclearBatchメソッドを使用します。このメソッドは標準のStatementインタフェースで指定されます。これは標準PreparedStatementインタフェースとCallableStatementインタフェースで拡張されています。

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

- バッチが処理されるとき、操作は、バッチに入れられた順に実行されます。

- addBatchをコールした後、executeUpdateをコールする前に、executeBatchまたはclearBatchをコールする必要があります。コールしないと、SQL例外が発生します。

- clearBatchまたはexecuteBatchをコールすると、文バッチは空にリセットされます。

- 接続がROLLBACK要求を受信すると、文のバッチが空にリセットされません。リセットするには、clearBatchを明示的にコールする必要があります。

注意:

- Oracle Database 11gでOracleバッチ更新を使用する場合、ロールバック後にコードで明示的にバッチを消去する必要はありません。ただし、ロールバック後にclearBatchメソッドをコールしてもかまいません。

- 以前のリリースでOracleバッチ更新を使用する場合、ロールバック後にclearBatchメソッドをコールして、明示的にバッチを消去する必要があります。

- ロールバック後のclearBatchメソッドのコールは、すべてのリリースで有効です。

- 文オブジェクトの現行結果セットがある場合、この結果セットはexecuteBatchコールによってクローズされます。

- clearBatchメソッドの戻り値はありません。

次の例では、前の例で示したプリコンパイルされたSQL文のaddBatchコールを繰り返した後、特定の条件でバッチを消去します。

...
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");

pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();

pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();

if (...condition...)
{
int[] updateCounts = pstmt.executeBatch();
...
}
else
{
pstmt.clearBatch();
...
}

標準バッチ処理のOracle実装の更新件数

文バッチが正常に処理された場合、文のexecuteBatchコールから戻される整数配列、つまり、更新件数配列には、常にバッチ操作1つに対して1つの要素が含まれます。標準バッチ更新のOracle実装では、配列要素の値は次のようになります。

- プリコンパイルされたSQL文のバッチの場合、バッチに含まれている個々の文によって影響を受けたデータベースの行数はわかりません。そのため、配列要素の値はすべて-2になります。JDBC 2.0仕様によれば、値-2は、操作は正常終了したが影響を受けた行数は不明であることを示します。

- 一般的な文のバッチの場合、配列には、各操作で影響を受けた行数を示す実際の更新件数を格納します。標準バッチのOracle実装では、一般的な文の場合のみ、実際の更新件数がわかります。

- コール可能な文のバッチの場合、サーバーは、各操作で影響を受けた行数に関係なく、更新件数として常に値1を戻します。

コードの側では、バッチの正常な処理に対して、配列要素に-2、1または実際の更新件数のいずれが設定されても処理できるように準備しておく必要があります。正常なバッチ処理では、配列にはすべて-2が含まれるか、すべて1が含まれるか、またはすべて正の整数が含まれます。

例23-2は、標準バッチ更新の使用方法を示しています。

例23-2 標準バッチ更新

この例は、前の項のサンプル・コードを組み合せたもので、次の処理を行います。

1. 自動コミット・モードの無効化。どちらかのバッチ更新モデルを使用する場合、無効にする必要があります。

2. PreparedStatementオブジェクトの作成。

3. PreparedStatementオブジェクトに関連付けられたバッチへの操作の追加。

4. バッチの処理。

5. バッチの操作のコミット。

conn.setAutoCommit(false);

PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");

pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();

pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();

int[] updateCounts = pstmt.executeBatch();

conn.commit();

pstmt.close();
...

更新件数配列を処理して、バッチが正常に処理されたかどうかを判断できます。

標準バッチ処理のOracle実装におけるエラー処理

executeBatchがコールされたとき、バッチ処理された操作のうち1つでも失敗したり、結果セットを戻そうとしたりすると、処理は停止し、java.sql.BatchUpdateExceptionが生成されます。

バッチ例外の後、BatchUpdateExceptionオブジェクトのgetUpdateCountsメソッドを使用して、更新件数配列を取り出せます。このメソッドからは、executeBatchメソッドと同じように、更新件数のint配列が戻されます。標準バッチ更新のOracle実装では、バッチが処理された後の更新件数配列の内容は次のようになります。

- プリコンパイルされたSQL文バッチの場合、どの操作が失敗したかはわかりません。配列には、バッチ内の各操作に対応して1つの要素があり、各要素は-3の値を持っています。JDBC 2.0仕様では、-3という値は、操作が正常に完了しなかったことを示します。この場合、実際に失敗したのはおそらくたった1つの操作ですが、それがどの操作であったかJDBCドライバにはわからないため、バッチ処理されたすべての操作に障害のラベル付けが行われます。
この場合、必ずROLLBACK操作を実行する必要があります。

- 一般的な文のバッチまたはコール可能文のバッチの場合、更新件数配列は、エラーの時点までの実際の更新件数を格納する、部分的な配列になります。標準バッチ更新のOracle実装では、Oracle JDBCは一般の文およびコール可能文の本当の意味でのバッチ処理を使用できないので、実際の更新件数がわかります。
たとえば、バッチに20の操作が含まれているとき、最初の13は正常終了し、14番目で例外が生成された場合、更新件数配列には13の要素が含まれ、正常終了した操作の実際の更新件数が設定されます。

この場合、正常終了した操作をコミットすることも、ロールバックすることもできます。

コードの側では、例外が発生した場合、バッチの失敗した処理に対して、配列要素に-3または実際の更新件数のどちらが設定されても処理できるように準備しておく必要があります。失敗したバッチ処理では、すべてに-3が含まれる完全な配列か、正の整数が含まれる部分配列が作成されます。

バッチ処理される文とバッチ処理されない文の混在

文オブジェクトに操作の保留バッチがある場合、通常のバッチ処理されない操作の処理を行うためにexecuteUpdateをコールできません。

ただし、文バッチに操作を追加する前か、バッチを処理した後で、バッチ処理されない操作を処理する場合は、バッチ処理される操作とバッチ処理されない操作を単一文オブジェクトに混在させることができます。つまり、文オブジェクトのexecuteUpdateは、バッチ更新が空のときにのみコールできます。バッチが空でない場合、例外が生成されます。

たとえば、次のような順序は有効です。

...
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");

pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");

int scount = pstmt.executeUpdate();   // OK; no operations in pstmt batch

pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();                    // Now start a batch

pstmt.setInt(1, 4000);
pstmt.setString(2, "Stan Leland");
pstmt.addBatch();

int[] bcounts = pstmt.executeBatch();

pstmt.setInt(1, 5000);
pstmt.setString(2, "Amy Feiner");

int scount = pstmt.executeUpdate();   // OK; pstmt batch was executed
...

ある文オブジェクトのバッチ処理されない操作と、別の文オブジェクトのバッチ処理される操作を、コード上に混在させることはできます。異なる文オブジェクトは、バッチ更新操作に関して、互いに無関係です。COMMIT要求は、バッチ処理されない操作すべてと、処理済バッチの正常な操作すべてに影響を与えますが、保留バッチには影響を与えません。

早期バッチ・フラッシュ

早期バッチ・フラッシュは、キャッシュされたメタデータが変更されると発生します。キャッシュされたメタデータは、次のような様々な理由から変更されることがあります。

- 最初のバインドがNULLで後続のバインドが非NULLである場合。

- 最初は文字列としてスカラー型がバインドされ、後でスカラー型としてバインドされた場合。あるいはその逆の場合。

早期バッチ・フラッシュ・カウントは、次のexecuteUpdateメソッドまたはsendBatchメソッドの戻り値に追加されます。

以前の機能では、ここで取得できるすべてのバッチ・フラッシュ値が失われました。以前の機能に切り替えるには、次に示すようにAccumulateBatchResultプロパティをfalseに設定します。

java.util.Properties info = new java.util.Properties();
info.setProperty("user", "SCOTT");
info.setProperty("passwd", "TIGER");
// other properties
...

// property: batch flush type
info.setProperty("AccumulateBatchResult", "false");

OracleDataSource ods = new OracleDataSource();
ods.setConnectionProperties(info);
ods.setURL("jdbc:oracle:oci:@"");
Connection conn = ods.getConnection();

注意:
AccumulateBatchResultプロパティはデフォルトでtrueに設定されます。

例23-3は、早期バッチ・フラッシュを示しています。

例23-3 早期バッチ・フラッシュ

((OraclePreparedStatement)pstmt).setExecuteBatch (2);

pstmt.setNull (1, OracleTypes.NUMBER);
pstmt.setString (2, "test11");
int count = pstmt.executeUpdate (); // returns 0

/*
* Premature batch flush happens here.
*/
pstmt.setInt (1, 22);
pstmt.setString (2, "test22");
int count = pstmt.executeUpdate (); // returns 0

pstmt.setInt (1, 33);
pstmt.setString (2, "test33");
/*
*  returns 3 with the new batching scheme where as,
*  returns 2 with the old batching scheme.
*/
int count = pstmt.executeUpdate ();

その他のOracleパフォーマンス拡張機能

Oracle JDBCドライバでは、バッチ更新に加えて、次の拡張機能がサポートされています。これにより、データベースへのラウンドトリップが減少し、パフォーマンスが向上します。

- 行のプリフェッチ
行をプリフェッチすることにより、データがフェッチされるたびに複数行がフェッチされるので、データベースへのラウンドトリップが減少します。余分にフェッチされたデータは、後で使用するためにクライアント側バッファに格納されます。プリフェッチの行数は、目的に応じて設定できます。

- 列型の指定
問合せの実行および問合せ結果の取出しを行うときに、標準のJDBCプロトコルで生じる非効率性を回避できます。

- データベース・メタデータTABLE_REMARKS列の抑止
コストの高い外部結合操作を回避できます。

Oracleでは、これらのパフォーマンス拡張機能をサポートするために、接続プロパティ・オブジェクトにいくつかの拡張機能を提供します。これらの拡張機能により、remarksReportingフラグと、行プリフェッチとバッチ更新のデフォルト値を設定できます。

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

- LOBデータのプリフェッチ

- Oracle行プリフェッチの制限事項

- 列型の定義

- DatabaseMetaData TABLE_REMARKSのレポート

LOBデータのプリフェッチ

Oracle Database 11gリリース2(11.2) JDBCドライバより前のJDBCドライバの場合、1回のラウンドトリップでLOBデータを取得するには、データをVARCHAR2型としてフェッチする必要があります。つまり、OracleTypes.VARCHARまたはOracleTypes.LONGVARCHARを、JDBC defineColumnTypeメソッドとともに使用する必要があります。この手法の制限は、LOBデータをCHAR型としてフェッチする場合、ロケータをデータとともにフェッチすることができないということです。このため、アプリケーションがLOBデータを後から取得する場合、またはアプリケーションが他のLOB操作を実行する場合、アプリケーションがLOBロケータを取得できないため、LOBロケータを取得するためにラウンドトリップがもう1回必要になります。

注意:
LOBロケータでの配列操作は、JDBC APIでサポートされていません。

Oracle Database 11gリリースg (11.2) JDBCドライバの場合、通常のフェッチ操作中にロケータとともにLOBデータの始めをプリフェッチするのと同様に、LOBの長さやチャンク・サイズなどの使用頻度の高いメタデータをプリフェッチすることで、ラウンドトリップの回数を減らします。LOBが小さい場合、ただ1回のラウンドトリップでデータをすべてプリフェッチできる場合があります。select、パース、実行およびフェッチが1回のラウンドトリップで行われるため、パフォーマンスが大幅に向上します。LOBがプリフェッチ・サイズの5倍より大きい場合、チャンク・サイズを取得するためのラウンドトリップが必要ないだけなので、パフォーマンスはそれほど向上しません。

defaultLobPrefetchSize接続プロパティ

Oracle Database 11gリリース2(11.2)から、接続のためのデフォルトLOBプリフェッチ・サイズを設定するために使用できる新しい接続プロパティoracle.jdbc.defaultLobPrefetchSizeが導入されました。この接続プロパティは、定数OracleConnection.CONNECTION_PROPERTY_DEFAULT_LOB_PREFETCH_SIZEとして定義されています。このプロパティの値が、現行接続のデフォルトのLOBプリフェッチ・サイズとして使用されます。この接続プロパティのデフォルト値は-1です。文レベルでこのデフォルト値を変更する場合は、oracle.jdbc.OracleStatementインタフェースで定義されているsetLobPrefetchSizeメソッドを使用します。デフォルト値は、次の値に変更できます。

- 現行接続のLOBプリフェッチを無効にするには-1

- メタデータ専用のLOBプリフェッチを有効にするには0

- フェッチ操作中にロケータとともにプリフェッチするBLOBのバイト数およびCLOBの文字数を指定するには、0より大きな任意の値

LOBプリフェッチ・サイズを取り出すには、oracle.jdbc.OracleStatementインタフェースで定義されているgetLobPrefetchSizeメソッドを使用します。

defineColumnTypeメソッドを使用して列レベルでLOBプリフェッチ・サイズの値も設定できます。列レベルの値は、接続または文レベルで設定されているどの値よりも優先されます。

関連項目:
詳細は、JavaDocを参照してください。

注意:
LOBプリフェッチが接続レベルまたは文レベルで無効でない場合、列レベルでも無効にできません。

Oracle行プリフェッチの制限事項

最大のプリフェッチ量は設定されていません。デフォルト値は10です。問合せから予想される行数および列数に基づいて、値を増減させた方が適している場合もあります。Propertiesオブジェクトを使用して、接続のデフォルト行プリフェッチ値を設定できます。

Statementオブジェクトは、作成されると、関連付けられた接続から行のプリフェッチ設定のデフォルト値を受け取ります。接続の行プリフェッチ設定のデフォルト値を後で変更しても、文の行プリフェッチ設定は変更されません。

結果セットの列のデータ型が、データ・インタフェースから戻されたLONG、LONG RAWまたはLOB、つまりストリーム型の場合は、いずれの型の値も実際に読み取らなくても、文の行プリフェッチ設定はJDBCによって1に変更されます。

プリフェッチ・サイズの設定は、アプリケーションのパフォーマンスに影響を与える場合があります。プリフェッチ・サイズを大きくすると、全データの取得に必要なラウンドトリップ数は減りますが、メモリーの使用量は増えます。これは、問合せ内の列の数とサイズ、および戻されることが予想される行数に依存します。また、JDBCクライアント・マシンのメモリーおよびCPU負荷にも依存します。スタンドアロン・クライアント・アプリケーションの最適値は、負荷の大きいアプリケーション・サーバーの場合と異なります。ネットワーク接続の速度および待機時間も考慮してください。

注意:
Oracle Database 11gリリース1(11.1)以降、Thinドライバは、最初のラウンドトリップで、最初のprefetch_size行をサーバーからフェッチすることができます。これにより、SELECT文でラウンドトリップを1回減らせます。

10gリリース1(10.1)以上のOracle JDBCドライバにそれより前のリリースのOracle JDBCドライバからアプリケーションを移行する場合は、以前検討した最適化を再検討する必要があります。メモリーの使用量およびパフォーマンス特性が大きく変化している場合があるからです。

一意なキーを選択する問合せなどは、よく実行する処理です。そのような問合せは、行をゼロ個または1つ戻します。プリフェッチ・サイズを1に設定すると、メモリーおよびCPUの使用量は減り、ラウンドトリップ数は増えません。if(rs.next())のかわりにwhile(rs.next())を記述して余分なフェッチを要求するというミスを避けるよう、注意する必要があります。

JDBC Thinドライバを使用する場合、useFetchSizeWithLongColumn接続プロパティを使用してください。PARSE、EXECUTEおよびFETCHが単一のラウンドトリップ内で実行されるからです。

プリフェッチ・サイズのチューニングは、実際のアプリケーションの現実的な負荷に基づき、JVM内でのメモリー管理のチューニングに合せて行う必要があります。

注意:

- JDBC 2.0フェッチ・サイズApplication Program Interface(API)とOracle行プリフェッチAPIをアプリケーションで混在させることはできません。どちらも使用できますが、両方は使用できません。

- Oracle行フェッチ・サイズ値を設定すると、問合せ以外に、結果セットのrefreshRowメソッドによる結果セットの行の明示的な再フェッチ(scroll-sensitive/読取り専用、scroll-sensitive/更新可能およびscroll-insensitive/更新可能結果セットに関係します)行数およびscroll-sensitive結果セットのウィンドウ・サイズ(自動再フェッチの実行頻度に影響します)にも影響を与えることがあります。ただし、Oracle行フェッチ・サイズ値は、フェッチ・サイズの設定によってオーバーライドされます。

関連項目:
「サポートされている接続プロパティ」

列型の定義

Oracle Database 10gでは、defineColumnTypeの実装が大幅に変更されました。これまでは、defineColumnTypeはパフォーマンスの最適化とデータ型変換の強制実行の両方に使用されていました。以前のリリースでは、すべてのドライバがdefineColumnTypeのコールによる利点を得ていました。Oracle Database 10gから、JDBC Thinドライバはこの情報の提供を必要としなくなりました。JDBC Thinドライバは、defineColumnTypeをコールせずに最大のパフォーマンスを実現します。アプリケーションでdefineColumnTypeを使用すると、JDBC Oracle Call Interface(OCI)およびサーバー側内部ドライバのパフォーマンスが向上します。

コードでJDBC ThinドライバおよびJDBC OCIドライバの両方を使用する場合は、Thinドライバの使用時に接続プロパティdisableDefineColumnTypeをtrueに設定することで、defineColumnTypeメソッドを無効にできます。その結果、defineColumnTypeは無視されます。JDBC OCIまたはサーバー側内部ドライバを使用する場合は、この接続プロパティをtrueに設定しないでください。

また、defineColumnTypeを使用して、クライアント側が割り当てるメモリー量を制御することや、可変長データのサイズを制限することもできます。

問合せの列型を定義するには、次の手順を実行します。

1. 必要に応じて、StatementオブジェクトをOracleStatement、OraclePreparedStatementまたはOracleCallableStatementにキャストします。

2. 必要に応じて、StatementオブジェクトのclearDefinesメソッドを使用して、このStatementオブジェクトの以前の列定義を消去します。

3. 各列で、StatementオブジェクトのdefineColumnTypeメソッドをコールして次のパラメータを渡します。

- 列索引(整数)

- 型コード(整数)
java.sql.Typesクラスまたはoracle.jdbc.OracleTypesクラスのstatic定数を使用します(Types.INTEGER、Types.FLOAT、Types.VARCHAR、OracleTypes.VARCHAR、OracleTypes.ROWIDなど)。この2つのクラスで、標準型の型コードは同一です。

- 型名(文字列)
構造化オブジェクト、オブジェクト参照および配列の場合は、型名も指定する必要があります。たとえば、Employee、EmployeeRef、EmployeeArrayなどです。

- 最大フィールド・サイズ(整数)
オプションで、この列の最大データ長も指定できます。

構造化オブジェクト、オブジェクト参照または配列の列型を定義する場合、最大フィールド・サイズ・パラメータは指定できません。このパラメータを含めても、無視されます。

- 使用する形式(short)
オプションで、この列の使用する形式も指定できます。データベース・キャラクタ・セットを使用する場合はOraclePreparedStatement.FORM_CHARに、各国語キャラクタ・セットを使用する場合はOraclePreparedStatement.FORM_NCHARに設定します。このパラメータを省略した場合、デフォルトはFORM_CHARです。

たとえば、stmtをOracle文と仮定して、次のように使用します。

stmt.defineColumnType(column_index, typeCode);

列がVARCHARまたは等価な型で、長さの制限がわかっている場合は、次のようにします。

stmt.defineColumnType(column_index, typeCode, max_size);

列がNVARCHARで、元の最大長が必要、かつデータベース・キャラクタ・セットへの変換が要求される場合は、次のようにします。

stmt.defineColumnType(column_index, typeCode, 0,
OraclePreparedStatement.FORM_CHAR );

列が構造化オブジェクト、オブジェクト参照および配列の場合は、次のようにします。

stmt.defineColumnType(column_index, typeCode, typeName);

デフォルトのデータ長をすべて受け取る必要がない場合は、最大フィールド・サイズを設定します。標準JDBC StatementクラスのsetMaxFieldSizeメソッドをコールして、戻されるデータ量の制限を設定します。つまり、戻されるデータのサイズは、次の値の最小値になります。

- defineColumnTypeで設定された最大フィールド・サイズ

- setMaxFieldSizeで設定された最大フィールド・サイズ

- データ型固有の最大サイズ

この処理が終了した後に、文のexecuteQueryメソッドを使用して問合せを実行します。

注意:
必要な結果セットのすべての列に対してデータ型を指定する必要はありません。

例23-4は、この機能の使用方法を示しています。この例では、oracle.jdbc.*インタフェースがインポート済であることを前提にしています。

例23-4 列型の定義

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@localhost:1502:orcl");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

Statement stmt = conn.createStatement();
// Allocate only 2 chars for this column (truncation will happen)
((OracleStatement)stmt).defineColumnType(1, Types.VARCHAR, 2);
ResultSet rset = stmt.executeQuery("select ename from emp");
while (rset.next() )
System.out.println(rset.getString(1));
stmt.close();

この例が示すように、defineColumnTypeメソッドの起動では、StatementオブジェクトstmtをOracleStatementにキャストする必要があります。接続のcreateStatementメソッドは、defineColumnTypeメソッドとclearDefinesを持たず、型がjava.sql.Statementであるオブジェクトを戻します。これらのメソッドは、OracleStatement実装でのみ提供されています。

定義の拡張要素では、JDBC型を使用して目的の型を指定します。使用可能な列型は、列のOracle内部型によって異なります。

すべての列は、本来のJDBC型に定義できます。多くの場合、Types.CHARまたはTypes.VARCHAR型コードに定義できます。

表23-1は、defineColumnTypeメソッドで使用できる有効な列定義引数のリストです。

表23-1 有効な列型

列内のOracle SQL型

defineColumnTypeで定義できる型

NUMBER、VARNUM

BIGINT、TINYINT、SMALLINT、INTEGER、FLOAT、REAL、DOUBLE、NUMERIC、DECIMAL、CHAR、VARCHAR

CHAR、VARCHAR2

CHAR、VARCHAR

LONG

CHAR、VARCHAR、LONGVARCHAR

LONGRAW

LONGVARBINARY、VARBINARY、BINARY

RAW

VARBINARY、BINARY

DATE

DATE、TIME、TIMESTAMP、CHAR、VARCHAR

ROWID

ROWID

BLOB

VARBINARY、BINARY

CLOB

LONG、CHAR、VARCHAR

defineColumnTypeを列の元のデータ型で使用することは、常に可能です。

DatabaseMetaData TABLE_REMARKSのレポート

データベース・メタデータ・クラスのgetColumns、getProcedureColumns、getProceduresおよびgetTablesメソッドを使用してTABLE_REMARKS列をレポートすると、コストの高い外部結合を必要とするため処理が遅くなります。この理由でJDBCドライバは、デフォルトではTABLE_REMARKS列を報告しません。

OracleConnectionオブジェクトのsetRemarksReportingメソッドにtrue引数を渡すと、TABLE_REMARKSレポートが使用可能になります。

Java Propertiesオブジェクトを使用して接続を確立した場合、setRemarksReportingをコールするかわりに、remarksReporting Javaプロパティを設定することもできます。

標準java.sql.Connectionオブジェクトを使用している場合、setRemarksReportingを使用するには、オブジェクトをOracleConnectionにキャストする必要があります。

例23-5は、TABLE_REMARKSレポートを使用可能にする方法を示しています。

例23-5 TABLE_REMARKSレポート

connは標準Connectionオブジェクト名を表しています。次の文を使用するとTABLE_REMARKSレポートが使用可能になります。

( (oracle.jdbc.OracleConnection)conn ).setRemarksReporting(true);

getColumnsの考慮事項

シノニムが指定されている場合、デフォルトでは、getColumnsメソッドは列の情報を取り出しません。シノニムが指定されている場合に情報の取出しを可能にするには、次のように、接続でsetIncludeSynonymsメソッドをコールする必要があります。

( (oracle.jdbc.driver.OracleConnection)conn ).setIncludeSynonyms(true)

これによって、その接続での後続のgetColumnsメソッドのコールすべてにシノニムが含まれます。これは、setRemarksReportingと同じです。あるいは、includeSynonyms接続プロパティを設定できます。これは、remarksReporting接続プロパティと同じです。

ただし、includeSynonymsがtrueに設定されている場合、シノニムが存在すると、table_name列に戻されるオブジェクト名は、シノニム名であることに留意してください。これは、表名をgetColumnsに渡す場合でも同じです。

getProceduresおよびgetProcedureColumnsメソッドの考慮事項

JDBCバージョン1.1および1.2では、getProceduresおよびgetProcedureColumnsメソッドは、catalog、schemaPattern、columnNamePatternおよびprocedureNamePatternパラメータを同じ方法で処理します。これらのメソッドに関するOracleの定義では、パラメータの処理方法は次のように異なります。

- catalog
Oracleには複数カタログはありませんが、複数パッケージはあります。したがって、catalogパラメータは、パッケージ名として扱われます。これは入力(catalogパラメータ)と出力(戻されたResultSetのcatalog列)の両方に該当します。入力時に、構成" "(空の文字列)は、プロシージャと引数を、パッケージ(スタンドアロンのオブジェクト)なしで取得します。null値は、選択基準(スタンドアロン・オブジェクトとパッケージ化されたオブジェクトの両方に関する戻し情報)から除外されることを意味します。つまり、パーセント記号(%)を渡すのと同じ効果です。それ以外の場合は、catalogパラメータには、パッケージ名パターンを指定します。必要に応じてSQLワイルドカードを付けられます。

- schemaPattern
Oracleデータベース内のオブジェクトはすべてはスキーマを持つ必要があるため、スキーマを持たないオブジェクトの情報を戻すことには意味がありません。このため、構成" "(空の文字列)は、入力時に、現在のスキーマ、つまり現在接続しているスキーマを持つオブジェクトを意味するものと解釈されます。catalogパラメータの動作との整合性を取るため、nullは選択基準からスキーマを除外するものと解釈されます。つまり、%を渡すのと同じ効果です。SQLワイルドカードを使用したパターンとしても使用できます。

- procedureNamePatternおよびcolumnNamePattern
プロシージャと引数はすべて名前を持っているため、空の文字列(" ")はいずれのパラメータについても意味を持ちません。このため、構成" "を使用すると例外が発生します。他のパラメータの動作との整合性を取るため、nullはパーセント記号(%)を渡すのと同じ効果を持ちます。

24 OCI接続プーリング

Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバ接続プーリング機能は、JDBCクライアントの一部です。この機能は、OracleOCIConnectionPoolクラスによって提供されます。

JDBCアプリケーションでは、同時に複数のプールを保持できます。複数のプールを保持すると、複数のアプリケーション・サーバーや異なるデータソースの各プールに対応できます。JDBC OCIドライバで提供される接続プーリングでは、アプリケーションで少数の物理接続をすべて使用して、複数の論理接続を保持できます。この論理接続でのコールは、コールの時点で使用可能な物理接続にルーティングされます。

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

- OCIドライバ接続プーリング: 背景

- OCIドライバ接続プーリングと共有サーバーの比較

- OCI接続プールの定義

- OCI接続プールへの接続

- OCI接続プーリングのサンプル・コード

- 文の処理とキャッシュ

- JNDIおよびOCI接続プール

注意:
セッションの多重化が必要な場合は、OCI接続を使用してください。OCI接続を使用しない場合は、暗黙的接続キャッシュを使用することをお薦めします。

OCIドライバ接続プーリング: 背景

Oracle JDBC OCIドライバは、Oracleセッションおよび接続の細かな管理などのいくつかのトランザクション・モニター機能を提供します。ハイエンド・アプリケーション・サーバーまたはトランザクション・モニターでは、コール・レベルで少数の物理接続を通じて、複数のセッションを多重化できるため、接続とバックエンドのOracleサーバー・プロセスをプーリングすることで、高度な拡張性を実現できます。

OracleOCIConnectionPoolインタフェースで提供される接続プーリングは、物理接続プールの管理を見えなくさせ、セッションと接続が分離されたインタフェースを単純化します。Oracleセッションとは、OracleOCIConnectionPoolから取得されたOracleOCIConnectionオブジェクトです。接続プール自体は通常、はるかに小さい複数の物理接続共有プールで構成され、同じ数の専用サーバー・プロセスを含むバックエンド・サーバー・プールに変換されます。少ない数の共有接続とバックエンドOracleプロセスを含むこのプールを介して、はるかに多い数のOracleセッションを多重化できる点に注目してください。

OCIドライバ接続プーリングと共有サーバーの比較

ある意味では、OCIドライバ接続プーリングが中間層で提供する機能は、共有サーバー・プロセスがバックエンドで提供する機能と同じです。OCIドライバ接続プーリングでは、中間層でセッションの多重化ロジックを管理することで、専用サーバー・インスタンスが共有インスタンスと同じように動作します。したがって、専用サーバー・プロセスと専用サーバー・プロセスへの接続のプーリングは、中間層にあるOCI接続プールで制御されます。

OCI接続プーリングと共有サーバーの主な違いは、共有サーバーを使用する場合、通常はデータベース・インスタンス内のディスパッチャに対してクライアントから接続が行われることです。ディスパッチャは、クライアントからの要求を適切な共有サーバーにリダイレクトします。他方、OCI接続プールからの物理接続は、バックエンド・サーバー・プールにあるOracle専用サーバー・プロセスに対して中間層から直接確立されます。

OCI接続プールが有効なのは、中間層がマルチスレッドである場合のみです。各スレッドは、データベースに対して1つのセッションを保持できます。データベースに対する実際の接続は、OracleOCIConnectionPoolによって保持され、これらの接続は、専用データベース・サーバー・プロセスのプールも含めて、中間層のすべてのスレッドで共有されます。

OCI接続プールの定義

OCI接続プールは、アプリケーションの開始時に作成されます。プールから接続を作成する方法は、OracleDataSourceクラスを使用して接続を作成する方法とほぼ同じです。

OCI接続プールの作成には、OracleDataSourceクラスを拡張するoracle.jdbc.pool.OracleOCIConnectionPoolクラスを使用します。OracleOCIConnectionPoolインスタンスから、論理接続オブジェクトを取得できます。これらの接続オブジェクトは、OracleOCIConnectionクラス型です。このクラスは、OracleConnectionインタフェースを実装します。OracleOCIConnectionインスタンスから作成したStatementオブジェクトには、OracleConnectionインスタンスから作成したOracleStatementオブジェクトと同じフィールドおよびメソッドがあります。

次のコードは、OracleOCIConnectionPoolクラスのヘッダー情報を示します。

/*
* @param us  ConnectionPool user-id.
* @param p   ConnectionPool password
* @param name  logical name of the pool. This needs to be one in the
*                   tnsnames.ora configuration file.
@param config (optional)  Properties of the pool, if the default does not
suffice. Default connection configuration is min =1, max=1,
incr=0
Please refer setPoolConfig for property names.

Since this is optional, pass null if the default configuration
suffices.

* @return
*
* Notes: Choose a userid and password that can act as proxy for the users
*        in the getProxyConnection() method.

If config is null, then the following default values will take
effect
CONNPOOL_MIN_LIMIT = 1
CONNPOOL_MAX_LIMIT = 1
CONNPOOL_INCREMENT = 0

*/

public synchronized OracleOCIConnectionPool
(String       user,    String   password,  String name, Properties config)
throws SQLException

/*
* This will use the user-id, password and connection pool name values set
LATER using the methods setUser, setPassword, setConnectionPoolName.

* @return
*
* Notes:

No OracleOCIConnection objects can be created on
this class unless the methods setUser, setPassword, setPoolConfig
are invoked.
When invoking the setUser, setPassword later, choose a userid and
password that can act as proxy for the users
*   in the getProxyConnection() method.
*/
public synchronized OracleOCIConnectionPool ()
throws SQLException

oracle.jdbc.poolパッケージおよびoracle.jdbc.ociパッケージのインポート

OCI接続プールを作成する前に、Oracle OCI接続プーリング機能に次のパッケージをインポートする必要があります。

import oracle.jdbc.pool.*;
import oracle.jdbc.oci.*;

OCI接続プールの作成

次のコードは、cpoolという名前のOracleOCIConnectionPoolクラスのインスタンスを作成する方法を示します。

OracleOCIConnectionPool cpool = new OracleOCIConnectionPool
("SCOTT", "TIGER", "jdbc:oracle:oci:@(description=(address=(host=
myhost)(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))",
poolConfig);

poolConfigは、接続プールを指定する一連のプロパティです。poolConfigがNULLの場合は、デフォルト値が使用されます。たとえば、次の場合を考えてみましょう。

- poolConfig.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, "4");

- poolConfig.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, "10");

- poolConfig.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, "2");

コンストラクタ・コール以外にも、個々のメソッドを使用してユーザー、パスワードおよび接続文字列を指定して、OracleOCIConnectionPoolクラスのインスタンスを作成する方法もあります。

OracleOCIConnectionPool cpool = new OracleOCIConnectionPool ( );
cpool.setUser("SCOTT");
cpool.setPassword("TIGER");
cpool.setURL("jdbc:oracle:oci:@(description=(address=(host=
myhost)(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))");
cpool.setPoolConfig(poolConfig);  // In case you want to specify a different
// configuration other than the default
// values.

OCI接続プール・パラメータの設定

接続プールの構成は、次に示すOracleOCIConnectionPoolクラス属性によって決まります。

- CONNPOOL_MIN_LIMIT
プールで保持できる物理接続の最小数を指定します。

- CONNPOOL_MAX_LIMIT
プールで保持できる物理接続の最大数を指定します。

- CONNPOOL_INCREMENT
既存の接続がすべて使用中で、さらに接続が必要になったとき、オープンする物理接続の増分数を指定します。オープンしている物理接続の数が、そのプールについてオープンできる接続の最大数を超えない場合にのみ、接続がオープンされます。

- CONNPOOL_TIMEOUT
物理接続が切断されるまでのアイドル状態の時間を指定します。これは論理接続には影響しません。

- CONNPOOL_NOWAIT
この属性を有効に設定すると、プール内の最大数の接続が使用されている場合に、コールに物理接続が必要になるとエラーが返されます。この属性を無効に設定すると、接続が使用可能になるまでコールは待機します。この属性をtrueに設定した後で、falseにリセットすることはできません。

これらの属性はすべて動的に構成できます。したがって、アプリケーションでは現行ロード、つまりオープンしている接続の数と使用中の接続の数を読み取って、setPoolConfigメソッドを使用してこれらの属性を適切に調整できます。

注意:
CONNPOOL_MIN_LIMIT、CONNPOOL_MAX_LIMITおよびCONNPOOL_INCREMENTパラメータのデフォルト値は、それぞれ1、1および0です。

OCI接続プールのプロパティを構成するには、setPoolConfigメソッドを使用します。次は、OracleOCIConnectionPoolクラス属性の代表的な設定例です。

...
java.util.Properties p  = new java.util.Properties( );
p.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, "1");
p.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, "5");
p.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, "2");
p.put (OracleOCIConnectionPool.CONNPOOL_TIMEOUT, "10");
p.put (OracleOCIConnectionPool.CONNPOOL_NOWAIT, "true");
cpool.setPoolConfig(p);
...

これらの属性を設定するときは、次の規則に従ってください。

- CONNPOOL_MIN_LIMIT、CONNPOOL_MAX_LIMITおよびCONNPOOL_INCREMENTパラメータは必須です。

- CONNPOOL_MIN_LIMITの値はゼロより大きくしてください。

- CONNPOOL_MAX_LIMITは、CONNPOOL_MIN_LIMITとCONNPOOL_INCREMENTを足した値以上にしてください。

- CONNPOOL_INCREMENTの値はゼロ以上にしてください。

- CONNPOOL_TIMEOUTの値はゼロより大きくしてください。

- CONNPOOL_NOWAITは、trueまたはfalseにしてください。

関連項目:
Oracle Call Interfaceプログラマーズ・ガイド

OCI接続プール・ステータスのチェック

接続プールのステータスをチェックするには、OracleOCIConnectionPoolクラスの次のメソッドを使用します。

- int getMinLimit()
プールで保持できる物理接続の最小数を取得します。

- int getMaxLimit()
プールで保持できる物理接続の最大数を取得します。

- int getConnectionIncrement()
既存の接続がすべて使用中に、コールに接続が必要になったときにオープンする物理接続の増分数を取得します。

- int getTimeout()
プールの物理接続が切断されるまでのアイドル状態の時間(秒単位)を取得します。接続の持続時間は最低使用頻度(LRU)アルゴリズムに基づいて決定されます。

- String getNoWait()
NOWAITプロパティが有効かどうかを取得します。trueまたはfalseの文字列が戻されます。

- int getPoolSize()
オープンしている物理接続の数を取得します。統計分析用にあくまで目安として使用してください。

- int getActiveSize()
オープンしていて、かつ使用中である物理接続の数を取得します。統計分析用にあくまで目安として使用してください。

- boolean isPoolCreated()
プールが作成されているかどうかを取得します。実際にプールが作成されるのは、OracleOCIConnection (user, password, url, poolConfig)をコールしたとき、またはOracleOCIConnection()をコールした後にsetUser、setPasswordおよびsetURLを実行したときです。

OCI接続プールへの接続

OracleOCIConnectionPoolクラスは、getConnectionメソッドをコールして、OracleOCIConnectionクラスのインスタンスを作成します。このインスタンスは1つの接続を表します。

OracleOCIConnectionクラスはOracleConnectionクラスを拡張したものなので、このクラスの機能も持っています。ユーザー・セッションが終了したらOracleOCIConnectionオブジェクトをクローズしてください。そうしない場合は、プール・インスタンスがクローズされるときにクローズされます。

getConnectionをコールするには、次の2つの方法があります。

- OracleConnection getConnection()
ユーザー名とパスワードを指定しない場合、接続プールの作成に使用されたデフォルトのユーザー名とパスワードを使用して、接続オブジェクトが作成されます。

- OracleConnection getConnection(String user, String password)
このメソッドを使用すると、指定されたユーザー名とパスワードで識別される論理接続を取得します。このユーザー名とパスワードは、プールの作成に使用されたものとは異なります。

次のコードは、オーバーロードされたgetConnectionメソッドのシグネチャを示します。

public synchronized OracleConnection getConnection( )
throws SQLException

/*
* For getting a connection to the database.
*
* @param us  Connection user-id
* @param p   Connection password
* @return     connection object
*/
public synchronized OracleConnection getConnection(String us, String p)
throws SQLException

OracleConnectionの拡張機能として、ユーザーのパスワードを変更するために次のような新しいメソッドがOracleOCIConnectionに追加されています。

void passwordChange (String user, String oldPassword, String newPassword)

OCI接続プーリングのサンプル・コード

次のコードは、サンプル・アプリケーションでのOCI接続プールの使用方法を示しています。

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import oracle.jdbc.OracleDriver;
import oracle.jdbc.pool.OracleOCIConnectionPool;

public class conPoolAppl extends Thread
{
public static final String query = "SELECT object_name FROM all_objects WHERE rownum < 300";
static public void main(String args[]) throws SQLException
{
int _maxCount = 10;
Connection []conn = new Connection[_maxCount];
try
{
DriverManager.registerDriver(new OracleDriver());

String s = null;   //System.getProperty ("JDBC_URL");

//String url = ( s == null ? "jdbc:oracle:oci8:@orcl" : s);
String url = "jdbc:oracle:oci8:@orcl.rmmslang.com";

OracleOCIConnectionPool cpool = new OracleOCIConnectionPool("scott", "tiger", url, null);

// Print out the default configuration for the OracleOCIConnectionPool
System.out.println ("-- The default configuration for the OracleOCIConnectionPool --");
displayPoolConfig(cpool);

//Set up the initial pool configuration
Properties p1  = new Properties();
p1.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, Integer.toString(1));
p1.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, Integer.toString(_maxCount));
p1.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, Integer.toString(1));

// Enable the initial configuration
cpool.setPoolConfig(p1);

Thread []t = new Thread[_maxCount];
for (int i = 0; i < _maxCount; ++i)
{
conn[i] = cpool.getConnection("scott", "tiger");
if ( conn[i] == null )
{
System.out.println("Unable to create connection.");
return;
}
t[i] = new conPoolAppl (i, conn[i]);
t[i].start ();
//displayPoolConfig(cpool);
}

((conPoolAppl)t[0]).startAllThreads ();
try
{
Thread.sleep (200);
}
catch (Exception ea) {}

displayPoolConfig(cpool);
for (int i = 0; i < _maxCount; ++i)
t[i].join ();
}
catch(Exception ex)
{
System.out.println("Error: " + ex);
ex.printStackTrace ();
return;
}
finally
{
for (int i = 0; i < _maxCount; ++i)
if (conn[i] != null)
conn[i].close ();
}
} //end of main

private Connection m_conn;
private static boolean m_startThread = false;
private int m_threadId;

public conPoolAppl (int i, Connection conn)
{
m_threadId = i;
m_conn = conn;
}

public void startAllThreads ()
{
m_startThread = true;
}

public void run ()
{
while (!m_startThread) Thread.yield ();
try
{
doQuery (m_conn);
}
catch (SQLException ea)
{
System.out.println ("*** Thread id: " + m_threadId);
ea.printStackTrace ();
}
} // end of run

private static void doQuery (Connection conn) throws SQLException
{
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = conn.prepareStatement (query);
rs = pstmt.executeQuery ();
while (rs.next ())
{
//System.out.println ("Object name: " +rs.getString (1));
}
}
catch (Exception ea)
{
System.out.println ("Error during execution: " +ea);
ea.printStackTrace ();
}
finally
{
if (rs != null)
rs.close ();
if (pstmt != null)
pstmt.close ();
if (conn != null)
conn.close ();
}
}  // end of doQuery (Connection)

// Display the current status of the OracleOCIConnectionPool
private static void displayPoolConfig (OracleOCIConnectionPool cpool) throws SQLException
{
System.out.println (" Min poolsize Limit: " + cpool.getMinLimit());
System.out.println (" Max poolsize Limit: " + cpool.getMaxLimit());
/*
System.out.println (" Connection Increment: " + cpool.getConnectionIncrement());
System.out.println (" NoWait: " + cpool.getNoWait());
System.out.println (" Timeout: " + cpool.getTimeout());
*/
System.out.println (" PoolSize: " + cpool.getPoolSize());
System.out.println (" ActiveSize: " + cpool.getActiveSize());
}

}  // end of class conPoolAppl

文の処理とキャッシュ

文キャッシュは、OracleOCIConnectionPoolでサポートされます。キャッシュを使用すると、カーソルをオープン、解析およびクローズする必要がなくなるため、パフォーマンスが向上します。OracleOCIConnection.prepareStatement ("a_SQL_query")を処理すると、SQL問合せに一致する文が文キャッシュから検索されます。一致する文が見つかった場合は、別のStatementオブジェクトを作成するかわりに、同じStatementオブジェクトを再利用できます。キャッシュ・サイズは動的に増減できます。デフォルトのキャッシュ・サイズは0(ゼロ)です。

注意:
OracleOCIConnectionクラスから作成したOracleStatementオブジェクトは、OracleConnectionから作成したオブジェクトと同じように動作します。

JNDIおよびOCI接続プール

Java Naming and Directory Interface(JNDI)機能によりJavaオブジェクトのプロパティが存続するため、そのオブジェクトの新しいインスタンスを、それらのプロパティを使用して作成することができます(例: オブジェクトのクローニングなど)。利点は、古いオブジェクトを解放して、正確に同じプロパティを持つ新しいオブジェクトを後で作成できることです。InitialContext.lookupメソッドは永続ストアからプロパティを取得し、そのプロパティを使用して新しいオブジェクトを作成しますが、InitialContext.bindメソッドは、ファイルまたはデータベースにあるプロパティを存続させます。

JNDI機能を使用して、OracleOCIConnectionPoolオブジェクトをバインドしたり、検索したりすることができます。OracleOCIConnectionPoolで新しくインタフェースをコールする必要はありません。

25 Oracleアドバンスト・キューイング(AQ)

Oracleアドバンスト・キューイング(AQ)は、データベース統合型のメッセージ・キューイング機能を提供します。Oracle Streams上で構築され、Oracleデータベースの機能を最適化して、メッセージを永続的に格納し、異なるコンピュータやデータベース上のキューにメッセージを伝播し、Oracle Netサービス、HTTPおよびHTTPSを使用してメッセージを送信できます。Oracle AQはデータベース表に実装されるため、運用上の利点である高可用性、スケーラビリティ、信頼性のすべてがキュー・データにも適用されます。この章では、Oracle AQへのJavaインタフェースに関する情報を提供します。

注意:
Oracle Database 11gリリース2(11.2)では、XMLTypeキューのサポートが追加されました。Oracle Database 11gリリース1(11.1)までは、サポートされているキューの型は、RAW、ADTおよびANYDATA型でした。

関連項目:
Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド

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

- Oracleアドバンスト・キューイングの機能とフレームワーク

- データベースの変更

- AQ非同期イベント通知

- メッセージの作成

- メッセージのエンキュー

- メッセージのデキュー

- 例: エンキューとデキュー

Oracleアドバンスト・キューイングの機能とフレームワーク

Oracle JDBCパッケージであるoracle.jdbc.aqは、高速JavaインタフェースをAQに提供しています。このパッケージには、次のものが含まれています。

- クラス

- AQDequeueOptions
デキュー操作で利用可能なオプションを指定します。

- AQEnqueueOptions
エンキュー操作で利用可能なオプションを指定します。

- AQFactory
AQのファクトリ・クラスです。

- AQNotificationEvent
通知を有効にするよう登録したキューに新しいメッセージがエンキューされると作成されます。

- インタフェース

- AQAgent
キューのユーザーや、メッセージのプロデューサまたはコンシューマを、表したり特定したりするために使用します。

- AQMessage
エンキューまたはデキュー対象のメッセージを表します。

- AQMessageProperties
相関、送信者、遅延、有効期限、受信者、優先度、順序付けなどのメッセージ・プロパティが含まれます。

- AQNotificationListener
AQ通知イベントを受信するためのリスナー・インタフェースです。

- AQNotificationRegistration
特定のキューに新しいメッセージがエンキューされた場合に通知を受けることを表します。

これらのクラスとインタフェースを使用して、既存のキューにアクセスしたり、メッセージを作成したり、メッセージをエンキューおよびデキューできます。

注意:
Oracle JDBCドライバには、キューを作成するためのAPIは一切用意されていません。キューは、DBMS_AQADM PL/SQLパッケージを使用して作成する必要があります。

関連項目:
APIの詳細は、Javadocを参照してください。

http://download.oracle.com/otn/utilities_drivers/jdbc/111060/doc/javadoc/index.html

データベースの変更

この章で使用されているコードの抜粋では、ユーザーSCOTTがデータベースに接続しているものとします。そのため、データベース内でSCOTTに次の権限を付与する必要があります。

GRANT EXECUTE ON DBMS_AQ to SCOTT;
GRANT EXECUTE ON DBMS_AQADM to SCOTT;
GRANT AQ_ADMINISTRATOR_ROLE TO SCOTT;
GRANT ADMINISTER DATABASE TRIGGER TO SCOTT;

メッセージをエンキューおよびデキューする前に、データベース内にキューが存在する必要があります。手順は次のとおりです。

1. 次のようにキュー表を作成します。

BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
QUEUE_TABLE =>'scott.RAW_SINGLE_QUEUE_TABLE',
QUEUE_PAYLOAD_TYPE =>'RAW',
COMPATIBLE => '10.0');
END;

2. 次のようにキューを作成します。

BEGIN
DBMS_AQADM.CREATE_QUEUE(
QUEUE_NAME =>'scott.RAW_SINGLE_QUEUE',
QUEUE_TABLE =>'scott.RAW_SINGLE_QUEUE_TABLE',
END;

3. 次のようにキューを起動します。

BEGIN
DBMS_AQADM.START_QUEUE(
'scott.RAW_SINGLE_QUEUE',
END;

キューの停止やデータベースからのキュー表の削除が必要な場合があります。次の方法で対処できます。

1. 次のようにキューを停止します。

BEGIN
DBMS_AQADM.STOP_QUEUE(
scott.RAW_SINGLE_QUEUE',
END;

2. 次のようにデータベースからキュー表を削除します。

BEGIN
DBMS_AQADM.DROP_QUEUE_TABLE(
QUEUE_TABLE =>'scott.RAW_SINGLE_QUEUE_TABLE',
FORCE => TRUE
END;

AQ非同期イベント通知

JDBCアプリケーションでは次のことができます。

- AQネームスペースを登録し、エンキュー発生時に通知を受け取ります。その方法は次のとおりです。

public AQNotificationRegistration registerForAQEvents(
OracleConnection conn,
String queueName) throws SQLException
{
Properties globalOptions = new Properties();
String[] queueNameArr = new String[1];
queueNameArr[0] = queueName;
Properties[] opt = new Properties[1];
opt[0] = new Properties();
opt[0].setProperty(OracleConnection.NTF_AQ_PAYLOAD,"true");
AQNotificationRegistration[] regArr = conn.registerAQNotification(queueNameArr,opt,globalOptions);
AQNotificationRegistration reg = regArr[0];
return reg;
}

- データベース・イベントにサブスクリプションを登録し、イベントのトリガー時に通知を受け取ります。
登録されたクライアントは、イベントがトリガーされた場合または明示的なAQエンキューの場合に非同期に通知されます(または、通知希望を登録したキューに新規メッセージがエンキューされた場合)。クライアントはデータベースに接続されている必要はありません。

次のコードは、データベース・イベントにサブスクライブし、イベントのトリガー時に通知を受け取る方法を示します。

class DemoAQRawQueueListener implements AQNotificationListener
{
OracleConnection conn;
String queueName;
String typeName;
int eventsCount = 0;

public DemoAQRawQueueListener(String _queueName, String _typeName)
throws SQLException
{
queueName = _queueName;
typeName = _typeName;
conn = (OracleConnection)DriverManager.getConnection
(DemoAQRawQueue.URL, DemoAQRawQueue.USERNAME, DemoAQRawQueue.PASSWORD);
}

public void onAQNotification(AQNotificationEvent e)
{
try
{
AQDequeueOptions deqopt = new AQDequeueOptions();
deqopt.setRetrieveMessageId(true);
if(e.getConsumerName() != null)
deqopt.setConsumerName(e.getConsumerName());
if((e.getMessageProperties()).getDeliveryMode()
== AQMessageProperties.MESSAGE_BUFFERED)
{
deqopt.setDeliveryMode(AQDequeueOptions.DEQUEUE_BUFFERED);
deqopt.setVisibility(AQDequeueOptions.DEQUEUE_IMMEDIATE);
}
AQMessage msg = conn.dequeue(queueName,deqopt,typeName);
byte[] msgId = msg.getMessageId();
if(msgId != null)
{
String mesgIdStr = DemoAQRawQueue.byteBufferToHexString(msgId,20);
System.out.println("ID of message dequeued = "+mesgIdStr);
}
System.out.println(msg.getMessageProperties().toString());
byte[] payload = msg.getPayload();
if(typeName.equals("RAW"))
{
String payloadStr = new String(payload,0,10);
System.out.println("payload.length="+payload.length+", value="+payloadStr);
}
}
catch(SQLException sqlex)
{
System.out.println(sqlex.getMessage());
}
eventsCount++;
}
public int getEventsCount()
{
return eventsCount;
}
public void closeConnection() throws SQLException
{
conn.close();
}
}

- 次のようにリスナーに登録します。

AQNotificationRegistration reg = registerForAQEvents(conn,queueName+":BLUE");
DemoAQRawQueueListener demo_li = new DemoAQRawQueueListener(queueName,queueType);
reg.addListener(demo_li);

メッセージの作成

メッセージをエンキューするには、まずそのメッセージを作成する必要があります。AQメッセージは、AQMessageインタフェースを実装したクラスのインスタンスによって表されます。各AQメッセージには、一連のプロパティ(メタデータ)と1つのペイロード(データ)が含まれます。AQメッセージを作成するには次の操作を実行します。

1. 次のようにAQMessagePropertiesのインスタンスを作成します。

AQMessageProperties msgprop = AQFactory.createAQMessageProperties();

2. 次のようにプロパティ属性を設定します。

msgprop.setCorrelation("mycorrelation");
msgprop.setExceptionQueue("MY_EXCEPTION_QUEUE");
msgprop.setExpiration(0);
msgprop.setPriority(1);

3. 次のようにAQMessagePropertiesオブジェクトを使用してAQメッセージを作成します。

AQMessage mesg = AQFactory.createAQMessage(msgprop);

4. 次のようにペイロードを設定します。

byte[] rawPayload = "Example_Payload".getBytes();
mesg.setPayload(new oracle.sql.RAW(rawPayload));

AQメッセージのプロパティ

AQメッセージのプロパティは、AQMessagePropertiesインタフェースのインスタンスによって表されます。設定または取得できるメッセージ・プロパティは次のとおりです。

- デキュー試行回数: メッセージのデキューを試行した回数を示します。このプロパティは、設定できません。

- 相関: メッセージのエンキュー時に、そのメッセージのプロデューサによって提供されるIDです。

- 遅延: メッセージをいつまでWAITING状態にしておくかを示す秒数です。指定された遅延時間が経過すると、メッセージはREADY状態になり、デキューできるようになります。メッセージID(msgid)を使用してメッセージをデキューした場合、遅延時間の指定はオーバーライドされます。

注意:
バッファ・メッセージについては遅延はサポートされません。

- 配信モード: メッセージがバッファ・メッセージであるか永続メッセージであるかを示します。このプロパティは、設定できません。

- エンキュー時間: メッセージがエンキューされた時刻を示します。この値はシステムによって決定され、ユーザーが設定することはできません。

- 例外キュー: メッセージを正常に処理できない場合にメッセージの移動先となるキューの名前を指定します。メッセージが移動されるのは、次の2つの場合です。

- デキューに失敗した回数がmax_retriesを超えた場合。

- メッセージが期限切れになった場合。

- 有効期限: メッセージがREADY状態になってから、そのメッセージをデキューできなくなるまでの秒数。デキューされないまま期限切れとなったメッセージは、EXPIRED状態になって例外キューに移されます。

- メッセージ状態: メッセージがデキューされた時点のメッセージの状態を示します。このプロパティは、設定できません。

- 直前のキューにおけるメッセージID: 現在のメッセージを生成した最後のキューに入っているメッセージのIDです。メッセージがあるキューから別のキューに伝播された場合は、この属性により、メッセージの最後の伝播元となったキューのIDが特定されます。このプロパティは、設定できません。

- 優先度: メッセージの優先順位を指定します。マイナスの整数を含む任意の整数です。小さい値ほど、高い優先度を表します。

- 受信者リスト: 受信者を表すAQAgentオブジェクトのリストです。デフォルトの受信者は、キューのサブスクライバです。このパラメータは、複数コンシューマのキューに対してのみ有効です。

- 送信者: メッセージのエンキュー時にプロデューサによって指定される識別子です。これはAQAgentのインスタンスです。

- トランザクション・グループ: キューがトランザクション・グループ対応である場合に、メッセージのトランザクション・グループを示します。このプロパティは、dequeueArrayメソッドに対するコールが成功した後に設定されます。

AQメッセージのペイロード

AQメッセージのペイロードは、キューの型に応じ、AQMessageインタフェースのsetPayloadメソッドを使用して指定します。次のコードは、ペイロードの設定方法の例を示しています。

...
byte[] rawPayload = "Example_Payload".getBytes();
mesg.setPayload(new oracle.sql.RAW(rawPayload));
...

AQメッセージのペイロードを取得するには、次のようにgetPayloadメソッドまたは適切なgetXXXPayloadメソッドを使用します。

byte[] payload = mesg.getPayload();

これらのメソッドは、AQMessageインタフェースで定義されています。

例: メッセージの作成およびペイロードの設定

この項では、メッセージを作成しペイロードを設定する方法の例を示します。

例25-1 メッセージの作成およびペイロードの設定

この例では、AQMessagePropertiesのインスタンスの作成、プロパティ属性の設定、AQメッセージの作成およびペイロードの設定の方法を示します。

AQMessageProperties msgprop = AQFactory.createAQMessageProperties();
msgprop.setCorrelation("mycorrelation");
msgprop.setExceptionQueue("MY_EXCEPTION_QUEUE");
AQAgent ag = AQFactory.createAQAgent();
ag.setName("MY_SENDER_AGENT_NAME");
ag.setAddress("MY_SENDER_AGENT_ADDRESS");
msgprop.setSender(ag);
// handle multi consumer case:
if(recipients != null)
msgprop.setRecipientList(recipients);
System.out.println(msgprop.toString());
AQMessage mesg = AQFactory.createAQMessage(msgprop);
byte[] rawPayload = "Example_Payload".getBytes();
mesg.setPayload(new oracle.sql.RAW(rawPayload));

メッセージのエンキュー

メッセージを作成し、メッセージのプロパティとペイロードを設定したら、OracleConnectionインタフェースのenqueueメソッドを使用してメッセージをエンキューできます。メッセージをエンキューする前には、いくつかのエンキュー・オプションを指定できます。具体的には、AQEnqueueOptionsクラスを使用して、次のエンキュー・オプションを指定できます。

- 配信モード: 配信モードを指定します。配信モードは、永続(ENQUEUE_PERSISTENT)またはバッファ(ENQUEUE_BUFFERED)に設定できます。

- メッセージIDの取得: メッセージのエンキュー時にサーバーからメッセージIDを取得するかどうかを指定します。デフォルトでは、メッセージIDは取得されません。

- 変換: エンキューの前にメッセージに適用する変換を指定します。変換関数の戻り型は、キューの型と一致する必要があります。

注意:
変換は、DBMS_TRANSFORM.CREATE_TRANSFORMATION(...)を使用して、PL/SQL内で作成する必要があります。

- 可視性: エンキュー・リクエストの、トランザクション上の動作を指定します。このオプションのデフォルト値はENQUEUE_ON_COMMITです。この設定値は、エンキュー操作が現在のトランザクションの一部であることを示します。ENQUEUE_IMMEDIATEを指定した場合、エンキュー操作は自律型トランザクションとなり、操作の完了時にコミットされます。バッファ・メッセージの場合は、ENQUEUE_IMMEDIATEを使用する必要があります。

次のコードは、エンキュー・オプションを設定してメッセージをエンキューする方法の例を示しています。

...
AQEnqueueOptions opt = new AQEnqueueOptions();opt.setRetrieveMessageId(true);
conn.enqueue(queueName, opt, mesg);
...

メッセージのデキュー

エンキューされたメッセージをデキューするには、OracleConnectionインタフェースのdequeueメソッドを使用します。メッセージをデキューする前には、デキュー・オプションを設定する必要があります。具体的には、AQDequeueOptionsクラスを使用して、次のデキュー・オプションを指定できます。

- 条件: メッセージ・プロパティ、メッセージ・データ・プロパティおよびPL/SQLファンクションに基づいて条件式を指定します。デキュー条件は、SQL問合せのWHERE句に似た構文を使用し、Boolean式として指定します。

- コンシューマ名: これを指定すると、そのコンシューマ名に一致するメッセージのみがアクセスされます。

注意:
キューが単一コンシューマ・キューの場合は、このオプションを設定しないでください。

- 相関: デキュー操作に適用する相関基準(検索基準)を指定します。

- 配信フィルタ: デキューするメッセージの型を指定します。指定できるのは、バッファ・メッセージのみ(DEQEUE_BUFFERED)、永続メッセージのみ(DEQUEUE_PERSISTENT、デフォルト)またはその両方(DEQUEUE_PERSISTENT_OR_BUFFERED)です。

- デキューするメッセージのID: デキューするメッセージのメッセージIDを指定します。このオプションは、IDがわかっている一意のメッセージをデキューする場合に使用できます。

- デキュー・モード: デキュー操作に関連付けるロック動作を指定します。次のいずれかの値を指定できます。

- DequeueMode.BROWSE: ロックを取得せずにメッセージをデキューします。

- DequeueMode.LOCKED: トランザクションの完了まで持続する書込みロックをかけてメッセージをデキューします。

- DequeueMode.REMOVE: (デフォルト)メッセージをデキュー後に削除します。保持プロパティが永続であれば、メッセージはキュー内に保持されます。

- DequeueMode.REMOVE_NO_DATA: メッセージを、更新済または削除済としてマークします。

- 最大バッファ長: メッセージがRAWキューからデキューされる場合に、メッセージに割り当てることができる最大バイト数を指定します。デフォルトの最大値はDEFAULT_MAX_PAYLOAD_LENGTHですが、これはゼロを除く任意の他の値に変更できます。メッセージ全体を格納できるほどバッファが大きくない場合、超過したバイト数は警告なしに無視されます。

- ナビゲーション: どの位置のメッセージを取得対象とするかを指定します。次のいずれかの値を指定できます。

- NavigationOption.FIRST_MESSAGE: 検索基準に一致するメッセージのうち、利用可能な最初のメッセージをデキューします。

- NavigationOption.NEXT_MESSAGE: (デフォルト)検索基準に一致する、次のデキュー可能なメッセージをデキューします。直前のメッセージがメッセージ・グループに属している場合は、そのメッセージ・グループ内で検索基準に一致する、次のデキュー可能なメッセージをデキューします。

- NavigationOption.NEXT_TRANSACTION: 現在のトランザクション・グループ内のメッセージをスキップし、次のトランザクション・グループの最初のメッセージをデキューします。この設定を使用できるのは、キューでメッセージのグループ化が可能な場合のみです。

- メッセージIDの取得: デキューするメッセージのメッセージIDを取得する必要があるかどうかを指定します。デフォルトでは取得されません。

- 変換: デキューの後にメッセージに適用する変換を指定します。変換のソース型は、キューの型と一致する必要があります。

注意:
変換は、DBMS_TRANSFORM.CREATE_TRANSFORMATION(...)を使用して、PL/SQL内で作成する必要があります。

- 可視性: メッセージを、現在のトランザクションの一部としてデキューするかどうかを指定します。次のいずれかの値を指定できます。

- VisibilityOption.ON_COMMIT: (デフォルト)現在のトランザクションの一部としてデキューします。

- VisibilityOption.IMMEDIATE: 操作の完了時にコミットされる自律型トランザクションとしてデキューします。

注意:
デキュー・モードがDequeueMode.BROWSEの場合、可視性オプションは無視されます。配信フィルタがDEQUEUE_BUFFEREDまたはDEQUEUE_PERSISTENT_OR_BUFFEREDである場合、このオプションはVisibilityOption.IMMEDIATEに設定する必要があります。

- 待機: 検索基準に一致するメッセージが1つもない場合にデキュー操作に適用する待機時間を指定します。デフォルト値のDEQUEUE_WAIT_FOREVERは、デキュー操作を無期限に待機状態にすることを示します。DEQUEUE_NO_WAITに設定した場合、デキュー操作は待機状態になりません。数値を指定した場合、デキュー操作は指定された秒数の間待機状態になります。

注意:
DEQUEUE_WAIT_FOREVERを指定すると、デキュー操作は検索基準に一致するメッセージがキュー内でデキュー可能になるまで待機状態が続きます。ただし、OracleConnectionオブジェクトに対してcancelメソッドをコールすると、デキュー操作を中断できます。

次のコードは、デキュー・オプションを設定してメッセージをデキューする方法の例を示しています。

...
AQDequeueOptions deqopt = new AQDequeueOptions();
deqopt.setRetrieveMessageId(true);
deqopt.setConsumerName(consumerName);
AQMessage msg = conn.dequeue(queueName,deqopt,queueType);

例: エンキューとデキュー

この項では、メッセージのエンキュー方法とデキュー方法を、いくつかの例で示します。

例25-2ではメッセージのエンキュー方法を、例25-3ではメッセージのデキュー方法を示しています。

例25-2 単一メッセージのエンキュー

この例では、キューにアクセスし、メッセージを作成して、メッセージをエンキューする方法を示しています。

AQMessageProperties msgprop = AQFactory.createAQMessageProperties();
msgprop.setPriority(1);
msgprop.setExceptionQueue("EXCEPTION_QUEUE");
msgprop.setExpiration(0);
AQAgent agent = AQFactory.createAQAgent();
agent.setName("AGENTNAME");
agent.setAddress("AGENTADDRESS");
msgprop.setSender(agent);
AQMessage mesg = AQFactory.createAQMessage(msgprop);
mesg.setPayload(buffer); // where buffer is a byte array (for a RAW queue)
AQEnqueueOptions options = new AQEnqueueOptions();
conn.enqueue("SCOTT.MY_QUEUE", options, mesg);

例25-3 単一メッセージのデキュー

この例では、キューにアクセスし、デキュー・オプションを設定して、メッセージをデキューする方法を示しています。

AQDequeueOptions options = new AQDequeueOptions();
options.setDeliveryFilter(AQDequeueOptions.DeliveryFilter.BUFFERED);
AQMessage mesg = conn.dequeue("SCOTT.MY_QUEUE", options, "RAW");

26 データベース変更通知

一般に、中間層データ・キャッシュは、バックエンド・データベース・サーバーの一部のデータを複製します。その目的は、データベースに対する冗長な問合せを回避することです。ただし、これが効率的なのは、データベース内でのデータの変更頻度が非常に低い場合に限られます。データベース内でデータが変更された際には、データ・キャッシュを更新するか、無効にする必要があります。11gリリース1(11.1)から、各Oracle JDBCドライバは、Oracle Databaseのデータベース変更通知機能をサポートしています。この機能を使用すると、JDBCドライバから無効化イベントを受信することにより、多重化システムのデータ・キャッシュを可能なかぎり最新の状態に保つことができます。

JDBCドライバでは、SQL問合せをデータベースに登録して、次のイベントの発生時に通知を受け取ることができます。

- 問合せに関連付けられたオブジェクトに対するDMLまたはDDL変更。

- 結果セットに影響を与えるDMLまたはDDL変更。

通知は、DMLまたはDDLトランザクションのコミット時にパブリッシュされます(ローカル・トランザクションで行われた変更は、コミットされるまでイベントを生成しません)。

Oracle JDBCドライバのデータベース変更通知機能は、次のような流れで使用します。

1. 登録: まず登録エントリを作成します。

2. 問合せの関連付け: 登録エントリを作成したら、その登録エントリにSQL問合せを関連付けできます。これらの問合せは、登録エントリの一部となります。

3. 通知: 表または結果セットに変更が生じると、通知が作成されます。Oracleデータベースは専用のネットワーク接続を使用してこれらの通知をJDBCドライバに伝え、JDBCドライバはそれらの通知をJavaイベントに変換します。

これらに加え、ユーザーにCHANGE NOTIFICATION権限を付与することも必要です。たとえば、SCOTTというユーザー名を使用してデータベースに接続する場合は、データベース内で次のコマンドを実行する必要があります。

grant change notification to scott;

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

- 登録エントリの作成

- 登録エントリへの問合せの関連付け

- データベース変更イベントの通知

- 登録の削除

登録エントリの作成

登録エントリの作成は、1回かぎりのプロセスであり、現在使用中のトランザクションの外部で実行します。サーバーに登録エントリを作成するためのAPIは、専用のトランザクション内で実行され、即時にコミットされます。登録エントリの作成にはJDBC接続が必要ですが、その接続に登録エントリがアタッチされるわけではありません。登録エントリの作成後に接続をクローズしても、登録エントリ自体は有効な状態を維持します。Oracle RAC環境においては、登録エントリはすべてのノードに存在する永続的エンティティとなります。ノードがダウンした場合でも、登録エントリは存在し続け、表の変更時には通知を受けます。

登録エントリの作成方法は、次の2種類に分けられます。

- JDBCスタイルの登録: JDBCドライバを使用し、サーバー上に登録エントリを作成します。JDBCドライバは、サーバーからの通知を(専用チャネルを介して)リスニングする新しいスレッドを起動し、それらの通知メッセージをJavaイベントに変換します。その後、JDBCドライバは作成したエントリに登録されているすべてのリスナーに通知を送ります。

- PL/SQLスタイルの登録: 通知の処理にPL/SQLのストアド・プロシージャを使用する場合は、PL/SQLスタイルの登録エントリを作成します。JDBCスタイルの登録の場合と同様に、登録エントリに文(問合せ)をアタッチするにはJDBCドライバを使用します。ただし、通知はPL/SQLのストアド・プロシージャによって処理されるため、JDBCドライバはサーバーからの通知を受け取りません。

注意:
既存の登録エントリから特定の(1つの)オブジェクト(表)を削除する方法はありません。次善策としては、そのオブジェクトを含まない登録エントリを新規作成するか、そのオブジェクトに関連付けられているイベントを無視します。

JDBCスタイルの登録エントリの作成には、oracle.jdbc.OracleConnectionインタフェースのregisterDatabaseChangeNotificationメソッドを使用できます。このメソッドでは、optionsパラメータにより、特定の登録オプションを設定できます。設定できる登録オプションの一部を表26-1に示します。これらのオプションは、java.util.Propertiesオブジェクトを使用して設定します。これらのオプションは、oracle.jdbc.OracleConnectionインタフェースで定義されています。これらの登録オプションは、JDBCドライバによって作成される通知イベントに直接影響を与えます。データベース変更通知機能の使用方法は、例26-1に示しています。

registerDatabaseChangeNotificationメソッドは、指定されたオプションを反映した、新しいデータベース変更登録エントリをデータベース・サーバー内に作成します。このメソッドはDatabaseChangeRegistrationオブジェクトを返し、そのオブジェクトを使用して登録エントリに文が関連付けられます。このメソッドはさらに、通知を送信するためにデータベースによって使用されるリスナー・ソケットをオープンします。

注意:
別の登録エントリによって作成されたリスナー・ソケットがすでに存在している場合は、新しいデータベース変更登録エントリもそのソケットを使用します。

表26-1 データベース変更通知登録オプション

オプション

説明

DCN_IGNORE_DELETEOP

trueに設定された場合、DELETE操作が実行されてもデータベース変更イベントは生成されません。

DCN_IGNORE_INSERTOP

trueに設定された場合、INSERT操作が実行されてもデータベース変更イベントは生成されません。

DCN_IGNORE_UPDATEOP

trueに設定された場合、UPDATE操作が実行されてもデータベース変更イベントは生成されません。

DCN_NOTIFY_CHANGELAG

クライアントにトランザクションいくつ分までの遅延を許可するかを指定します。

注意: このオプションを0以外の値に設定した場合、DCN_NOTIFY_ROWIDSオプションをtrueに設定しても、ROWIDレベルの粒度の情報は一連のイベントで利用できなくなります。

DCN_NOTIFY_ROWIDS

データベース変更イベントに、操作タイプやROWIDなど、行レベルの詳細情報を含めます。

DCN_QUERY_CHANGE_NOTIFICATION

オブジェクト変更通知のかわりに、問合せ変更通知をアクティブにします。

注意: このオプションは、11.0データベースに対して実行する場合にのみ利用できます。

NTF_LOCAL_HOST

サーバーからの通知を受信するコンピュータのIPアドレスを指定します。

NTF_LOCAL_TCP_PORT

リスナー・ソケット用としてドライバに使用させるTCPポートを指定します。

NTF_QOS_PURGE_ON_NTFN

最初の通知イベント発生時に登録エントリを消去するかどうかを指定します。

NTF_QOS_RELIABLE

通知を永続的に維持するかどうかを指定します(trueにするとパフォーマンス・コストが高くなります)。

NTF_TIMEOUT

このオプションで秒数を指定すると、登録エントリは指定した秒数の経過後にデータベースによって自動的に消去されます。

すでに登録エントリが存在している場合は、getDatabaseChangeRegistrationメソッドを使用して、既存の登録エントリを新しいDatabaseChangeRegistrationオブジェクトにマップすることもできます。このメソッドは、PL/SQLを使用した登録エントリをすでに作成してあり、それに文を関連付ける場合に特に便利です。

関連項目:
APIの詳細は、Javadocを参照してください。

登録エントリへの問合せの関連付け

登録エントリの作成、または既存の登録エントリに対するマップが終わったら、登録エントリに問合せを関連付けることができます。登録エントリの作成と同様、登録エントリと問合せの関連付けは1回かぎりのプロセスであり、現在使用中の登録の外部で実行します。問合せの関連付けは、ローカル・トランザクションがロールバックされても実行されます。

登録エントリと問合せの関連付けは、OracleStatementクラスで定義されているsetDatabaseChangeRegistrationメソッドを使用して実行します。このメソッドは、DatabaseChangeRegistrationオブジェクトをパラメータとして取ります。次のコードは、登録エントリに問合せを関連付ける方法の例を示しています。

...
// conn is a OracleConnection object.
// prop is a Properties object containing the registration options.
DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotifictaion(prop);
...
Statement stmt = conn.createStatement();
// associating the query with the registration
((OracleStatement)stmt).setDatabaseChangeRegistration(dcr);
// any query that will be executed with the 'stmt' object will be associated with
// the registration 'dcr' until 'stmt' is closed or
// '((OracleStatement)stmt).setDatabaseChangeRegistration(null);' is executed.
...

データベース変更イベントの通知

データベース変更イベントを受け取るには、登録エントリにリスナーをアタッチします。データベース変更イベントが発生すると、データベース・サーバーはJDBCドライバに通知します。JDBCドライバは、新しいJavaイベントを作成し、通知対象の登録エントリを特定した後、その登録エントリにアタッチされているリスナーに通知を送ります。イベントには、変更されたデータベース・オブジェクトのオブジェクトIDと、変更の原因となった操作のタイプが含まれます。登録オプションによっては、行レベルの詳細情報も含まれます。その後、そのイベントを使用して、データ・キャッシュに関する判断を行うリスナー・コードを実行することもできます。

注意:
リスナー・コードは、JDBC通知メカニズムの処理速度を低下させないように作成する必要があります。データベースへの問合せによってデータ・キャッシュをリフレッシュするなど、リスナー・コードの処理時間が長い場合は、専用のスレッド内で実行する必要があります。

登録エントリにリスナーをアタッチするには、addListenerメソッドを使用します。次のコードは、登録エントリにリスナーをアタッチする方法の例を示しています。

...
// conn is a OracleConnection object.
// prop is a Properties object containing the registration options.
DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotifictaion(prop);
...
// Attach the listener to the registration.
// Note: DCNListener is a custom listener and not a predefined or standard
// lsiener
DCNListener list = new DCNListener();
dcr.addListener(list);
...

登録の削除

登録エントリをサーバーから削除し、ドライバ内のリソースをリリースするには、登録エントリを明示的に解除する必要があります。登録の解除には、作成時に使用したのとは別の接続を使用できます。登録の解除には、oracle.jdbc.OracleConnectionで定義されているunregisterDatabaseChangeNotificationメソッドを使用します。

このメソッドには、パラメータとしてDatabaseChangeRegistrationオブジェクトを渡す必要があります。このメソッドは、サーバーおよびドライバから登録を削除し、リスナー・ソケットをクローズします。

PL/SQLを使用するなどして、登録エントリをJDBCの外部で作成した場合は、DatabaseChangeRegistrationオブジェクトのかわりに登録IDを渡す必要があります。このメソッドは、サーバーから登録を削除しますが、ドライバ内のリソースは解放しません。

例

データベース変更通知機能の使用方法は、例26-1に示しています。この例では、ユーザーSCOTTがデータベースに接続しています。そのため、データベース内でこのユーザーに次の権限を付与する必要があります。

grant change notification to scott;

例26-1 データベース変更通知

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.jdbc.OracleStatement;
import oracle.jdbc.dcn.DatabaseChangeEvent;
import oracle.jdbc.dcn.DatabaseChangeListener;
import oracle.jdbc.dcn.DatabaseChangeRegistration;

public class DBChangeNotification
{
static final String USERNAME= "scott";
static final String PASSWORD= "tiger";
static String URL;

public static void main(String[] argv)
{
if(argv.length < 1)
{
System.out.println("Error: You need to provide the URL in the first argument.");
System.out.println("  For example: > java -classpath .:ojdbc5.jar DBChangeNotification \"jdbc:oracle:thin:
@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=yourhost.yourdomain.com)(PORT=1521))(CONNECT_DATA=
(SERVICE_NAME=yourservicename)))\"");

System.exit(1);
}
URL = argv[0];
DBChangeNotification demo = new DBChangeNotification();
try
{
demo.run();
}
catch(SQLException mainSQLException )
{
mainSQLException.printStackTrace();
}
}

void run() throws SQLException
{
OracleConnection conn = connect();

// first step: create a registration on the server:
Properties prop = new Properties();

// if connected through the VPN, you need to provide the TCP address of the client.
// For example:
// prop.setProperty(OracleConnection.NTF_LOCAL_HOST,"14.14.13.12");

// Ask the server to send the ROWIDs as part of the DCN events (small performance
// cost):
prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS,"true");
//
//Set the DCN_QUERY_CHANGE_NOTIFICATION option for query registration with finer granularity.
prop.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION,"true");

// The following operation does a roundtrip to the database to create a new
// registration for DCN. It sends the client address (ip address and port) that
// the server will use to connect to the client and send the notification
// when necessary. Note that for now the registration is empty (we haven't registered
// any table). This also opens a new thread in the drivers. This thread will be
// dedicated to DCN (accept connection to the server and dispatch the events to
// the listeners).
DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotification(prop);

try
{
// add the listenerr:
DCNDemoListener list = new DCNDemoListener(this);
dcr.addListener(list);

// second step: add objects in the registration:
Statement stmt = conn.createStatement();
// associate the statement with the registration:
((OracleStatement)stmt).setDatabaseChangeRegistration(dcr);
ResultSet rs = stmt.executeQuery("select * from dept where deptno='45'");
while (rs.next())
{}
String[] tableNames = dcr.getTables();
for(int i=0;i<tableNames.length;i++)
System.out.println(tableNames[i]+" is part of the registration.");
rs.close();
stmt.close();
}
catch(SQLException ex)
{
// if an exception occurs, we need to close the registration in order
// to interrupt the thread otherwise it will be hanging around.
if(conn != null)
conn.unregisterDatabaseChangeNotification(dcr);
throw ex;
}
finally
{
try
{
// Note that we close the connection!
conn.close();
}
catch(Exception innerex){ innerex.printStackTrace(); }
}

synchronized( this )
{
// The following code modifies the dept table and commits:
try
{
OracleConnection conn2 = connect();
conn2.setAutoCommit(false);
Statement stmt2 = conn2.createStatement();
stmt2.executeUpdate("insert into dept (deptno,dname) values ('45','cool dept')",
Statement.RETURN_GENERATED_KEYS);
ResultSet autoGeneratedKey = stmt2.getGeneratedKeys();
if(autoGeneratedKey.next())
System.out.println("inserted one row with ROWID="+autoGeneratedKey.getString(1));
stmt2.executeUpdate("insert into dept (deptno,dname) values ('50','fun dept')",
Statement.RETURN_GENERATED_KEYS);
autoGeneratedKey = stmt2.getGeneratedKeys();
if(autoGeneratedKey.next())
System.out.println("inserted one row with ROWID="+autoGeneratedKey.getString(1));
stmt2.close();
conn2.commit();
conn2.close();
}
catch(SQLException ex) { ex.printStackTrace(); }

// wait until we get the event
try{ this.wait();} catch( InterruptedException ie ) {}
}

// At the end: close the registration (comment out these 3 lines in order
// to leave the registration open).
OracleConnection conn3 = connect();
conn3.unregisterDatabaseChangeNotification(dcr);
conn3.close();
}

/**
* Creates a connection the database.
*/
OracleConnection connect() throws SQLException
{
OracleDriver dr = new OracleDriver();
Properties prop = new Properties();
prop.setProperty("user",DBChangeNotification.USERNAME);
prop.setProperty("password",DBChangeNotification.PASSWORD);
return (OracleConnection)dr.connect(DBChangeNotification.URL,prop);
}
}
/**
* DCN listener: it prints out the event details in stdout.
*/
class DCNDemoListener implements DatabaseChangeListener
{
DBChangeNotification demo;
DCNDemoListener(DBChangeNotification dem)
{
demo = dem;
}
public void onDatabaseChangeNotification(DatabaseChangeEvent e)
{
Thread t = Thread.currentThread();
System.out.println("DCNDemoListener: got an event ("+this+" running on thread "+t+")");
System.out.println(e.toString());
synchronized( demo ){ demo.notify();}
}
}

このコードは、Oracle Database 10gリリース2(10.2)でも動作します。このコードでは、表登録を使用しています。この場合、SELECT問合せを登録しても、登録されるのは問合せ自体ではなく、それに関与する表の名前です。つまり、表内の1行を選択した場合、それとは別の行が更新されていて、問合せの結果に影響がなくても、通知を受けることになります。

このコード例では、登録エントリをクローズせずにオープン状態のままにしておくと、データベース変更通知スレッドは動作を継続するようになっています。したがって、SCOTT.DEPT表を変更するDML問合せを(SQL*Plusなどから)起動およびコミットすると、Javaプログラムによって通知が出力されます。

第VI部

高可用性

この項では、Oracle Database 11gの高可用性機能について説明します。高速接続フェイルオーバーおよび透過的アプリケーション・フェイルオーバー(TAF)の機能について説明します。

第VI部の構成は次のとおりです。

- 第27章「高速接続フェイルオーバー」

- 第28章「透過的アプリケーション・フェイルオーバー」

27 高速接続フェイルオーバー

高速接続フェイルオーバーは、Oracle Database 11gの接続フェイルオーバー機能を、Java Database Connectivity(JDBC)アプリケーションがドライバに依存せずに利用できる方法を提供します。この章では、次の概念について説明します。

- 高速接続フェイルオーバーの概要

- 高速接続フェイルオーバーの使用

- 高速接続フェイルオーバーについて

- 高速接続フェイルオーバーとTAFの比較

注意:

- Oracle Database 11gリリース2 (11.2)から、この機能は非推奨となり、Universal Connection Pool (UCP) for JDBCがこれに置き換わりました。新しいアーキテクチャは、以前より強力でパフォーマンスも向上しているため、こちらを使用することをお薦めします。詳細は、次のリンクを参照してください。
http://www.oracle.com/technetwork/database/focus-areas/application-development/index-099369.html

http://download.oracle.com/docs/cd/B28359_01/java.111/e10788.pdf

- UCPを使用する場合は、暗黙的接続キャッシュを有効にして高速接続フェイルオーバーを使用しないでください。詳細は、次のリンクを参照してください。
http://www.oracle.com/technetwork/database/enterprise-edition/ucp-transition-guide-129515.pdf

高速接続フェイルオーバーの概要

高速接続フェイルオーバー・メカニズムは、暗黙的接続キャッシュ機能に依存しています。暗黙的接続キャッシュの詳細は、第21章「暗黙的接続キャッシュ」を参照してください。

高速接続フェイルオーバーの利点は、次のとおりです。

- ドライバからの独立性
高速接続フェイルオーバーは、JDBC ThinドライバおよびJDBC Oracle Call Interface(OCI)ドライバの両方をサポートしています。

- 暗黙的接続キャッシュとの統合
これら2つの機能は、ともに機能して相乗効果を発揮し、アプリケーションのパフォーマンスおよび高可用性を向上します。

- Oracle Real Application Clusters(Oracle RAC)との統合
これにより、優れたReal Application Clusters/高可用性イベント通知メカニズムが提供されます。

- アプリケーション・コードとの容易な統合
高速接続フェイルオーバーを使用可能にするのみで、他の構成は必要ありません。

高速接続フェイルオーバーの機能

高速接続フェイルオーバーを使用可能にすると、次の機能が提供されます。

- キャッシュ内の無効な接続のすばやい検出およびクリーン・アップ(DOWNイベント処理)

- 使用可能な接続のロード・バランシング(UPイベント処理)

- すべてのアクティブなOracle RACインスタンスへの実行時作業要求の分散

高速接続フェイルオーバーの使用

アプリケーションは、DataSourceインスタンスを通じて高速接続フェイルオーバーを管理します。

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

- 高速接続フェイルオーバーの前提条件

- 高速接続フェイルオーバー用のONSの構成

- 高速接続フェイルオーバーを使用可能にする

- 高速接続フェイルオーバーのステータスの問合せ

高速接続フェイルオーバーの前提条件

高速接続フェイルオーバーを使用するには、次の前提条件を満たしている必要があります。

- 暗黙的接続キャッシュが使用可能であること
高速接続フェイルオーバーは、JDBC接続キャッシュ・メカニズムとの組合せで動作します。これにより、アプリケーションは接続を管理して高可用性を確保します。

- アプリケーションがデータベースへの接続にサービス名を使用していること
アプリケーションはサービス識別子を使用できません。

- 基礎となるデータベースには、Oracle Database 11g Real Application Clusters(Oracle RAC)機能、または単一インスタンス・データベースかOracle RACのいずれかで構成されたOracle Data Guardがあること
フェイルオーバー・イベントが伝播しないと、接続フェイルオーバーは発生しません。

- JDBCが稼働しているノードでOracle Notification Service(ONS)が構成されており、使用可能であること
JDBCは、データベース・イベントの伝播およびJDBCへのイベントの通知を行うために、ONSに依存しています。

- JDBCインスタンスが稼働しているJava仮想マシン(JVM)で、oracle.ons.oraclehomeがORACLE_HOMEを指すように設定されていること

高速接続フェイルオーバー用のONSの構成

高速接続フェイルオーバーを使用するには、ONSを正しく構成する必要があります。ONSは、Oracle Database 11gの一部として出荷されます。詳細は、「ONSの構成」を参照してください。

リモートONSサブスクリプション

リモートONSサブスクリプションの利点は次のとおりです。

- すべてのJava中間層スタックに対するサポート

- クライアント・コンピュータではONSデーモンが必要ないので、このプロセスの管理が不要

- DataSourceプロパティを使用した簡単な構成

高速接続フェイルオーバーに対してリモートONSサブスクリプションを使用すると、アプリケーションはOracleDataSourceインスタンスの次のメソッドをコールします。

setONSConfiguration(String remoteONSConfig)

remoteONSConfigパラメータは、name=valueという形式の名前と値のペアのリストで、改行記号(\n)で区切られます。ここで、nameはnodes、walletfileまたはwalletpasswordのいずれかです。このパラメータには、少なくともnodesONS構成属性を指定してください。これはhost:portペアのリストで、各ペアはカンマ(,)で区切ります。ホストとポートは、Oracle RACノードで利用できるリモートONSデーモンを示します。

関連項目:
「ONSの構成」

Oracle Walletファイルとしてwalletfile属性が指定されると、ONSデーモンとの通信にSSLが使用される可能性があります。そのような場合、walletpassword属性が指定されなければ、シングル・サインオン(SSO)とみなされます。

次にいくつかの例を示します。odsはOracleDataSourceインスタンスであるとします。

ods.setONSConfiguration("nodes=racnode1.example.com:4200,racnode2.example.com:4200");

ods.setONSConfiguration("nodes=racnode1:4200,racnode2:4200\nwalletfile=/mydir/Wallet\nwalletpassword=mypasswd");

ods.setONSConfiguration("nodes=racnode1:4200,racnode2:4200\nwalletfile=/mydir/conf/Wallet");

高速接続フェイルオーバーを使用可能にする

アプリケーションは、DataSourceインスタンスから接続を取り出す前に、そのインスタンスに対してsetFastConnectionFailoverEnabled(true)をコールすることにより、高速接続フェイルオーバーを使用可能にします。

接続キャッシュを再初期化するときには高速接続フェイルオーバーを使用可能にできません。OracleDataSourceインスタンスを使用する前に使用可能にする必要があります。

例27-1に、高速接続フェイルオーバーを使用可能にする方法を示します。

注意:
キャッシュで高速接続フェイルオーバーを使用可能にすると、そのキャッシュの存続期間中は高速接続フェイルオーバーを使用不可にできません。

高速接続フェイルオーバーを使用可能にするには、次の操作が必要です。

- ONSを構成し起動します。ONSが正しく設定されていない場合、暗黙的接続キャッシュの作成は失敗し、最初のgetConnectionリクエストでONSExceptionがスローされます。

- OracleDataSourceに対して最初のgetConnectionリクエストを送信する前に、FastConnectionFailoverEnabledプロパティを設定します。高速接続フェイルオーバーが使用可能になっている場合、フェイルオーバーは接続キャッシュ内のすべての接続に適用されます。アプリケーションがConnection Cache Managerを使用して明示的に接続キャッシュを作成する場合、接続を取り出す前にFastConnectionFailoverEnabledを設定する必要があります。

- OracleDataSource urlプロパティを設定する際、サービス識別子ではなくサービス名を使用してください。

例27-1 高速接続フェイルオーバーの有効化

// declare datasource
ods.setUrl(
"jdbc:oracle:oci:@(DESCRIPTION=
(ADDRESS=(PROTOCOL=TCP)(HOST=cluster_alias)
(PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=service_name)))");
ods.setUser("scott");
ods.setConnectionCachingEnabled(true);
ods.setFastConnectionFailoverEnabled(true):
ctx.bind("myDS",ods);
ds=(OracleDataSource) ctx.lookup("MyDS");
try {
ds.getConnection();  // transparently creates and accesses cache
catch (SQLException SE {
}
}
...

高速接続フェイルオーバーのステータスの問合せ

アプリケーションは、高速接続フェイルオーバーが使用可能になっているかどうかを判断するために、OracleDataSource.getFastConnectionFailoverEnabledをコールします。フェイルオーバーが使用可能な場合はtrueが、それ以外の場合はfalseが戻されます。

高速接続フェイルオーバーについて

高速接続フェイルオーバーを使用可能に設定すると、メカニズムは自動なので、アプリケーションによる操作は必要ありません。この項では、接続フェイルオーバーがアプリケーションに提示される仕組みと、アプリケーションによるリカバリの手順を説明します。

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

- アプリケーションによる認識

- 実行される処理

アプリケーションによる認識

Oracle RACサービス障害がJDBCアプリケーションに伝播される前に、データベースはローカル・トランザクションをすでにロールバックしています。次に、キャッシュ・マネージャがすべての無効な接続をクリーン・アップします。無効な接続を保持しているアプリケーションがその接続を通して機能しようとすると、「SQLException, ORA-17008, クローズされた接続です。」を受け取ることがあります。

アプリケーションが「クローズされた接続です。」エラー・メッセージを受信した場合、次のことを実行する必要があります。

1. 接続要求を再試行します。古い接続はオープンでないため、これは必須です。

2. トランザクションを再実行します。接続がクローズする前に実行された作業はすべて失われています。

注意:
アプリケーションによってトランザクションをロールバックしないでください。アプリケーションが例外を受信した時点で、トランザクションはすでにデータベースでロールバックされています。

実行される処理

高速接続フェイルオーバーでは、キャッシュ内の各接続はサービス、インスタンス、データベースおよびホスト名へのマッピングを維持します。

データベースがOracle RACイベントを生成すると、そのイベントはJDBCが稼働中であるJVMに転送されます。JVM内のデーモン・スレッドがOracle RACイベントを受信し、それをConnection Cache Managerに転送します。次に、Connection Cache ManagerはOracle RACイベントの影響を受けるアプリケーションに対してSQL例外を発行します。

一般的なフェイルオーバーの例を次に示します。

1. データベース・インスタンスで障害が発生し、キャッシュ内にいくつかの失効した接続が残ります。

2. データベース内のOracle RACメカニズムがOracle RACイベントを生成し、そのイベントはJDBCが含まれているJVMに送信されます。

3. JVM内のデーモン・スレッドはOracle RACイベントの影響を受けるすべての接続を検出し、SQL例外によって接続がクローズされたことを通知し、オープンなトランザクションがあればすべてロールバックします。

4. 各接続はSQL例外を受信し、再試行します。

高速接続フェイルオーバーとTAFの比較

高速接続フェイルオーバーと透過的アプリケーション・フェイルオーバー(TAF)は、次の点で異なります。

- アプリケーションレベルでの接続の再試行
高速接続フェイルオーバーは、アプリケーションレベルでの接続の再試行をサポートしています。これにより、アプリケーションは接続のフェイルオーバーへの対応を制御できます。アプリケーションは接続を再試行するか、または例外を再発生させるかを選択できます。TAFでは、接続の再試行はOCI/Netレイヤーでのみサポートしています。

- 暗黙的接続キャッシュとの統合
高速接続フェイルオーバーは暗黙的接続キャッシュと高度に統合されているため、Connection Cache Managerはキャッシュを管理して高可用性を維持できます。たとえば、障害が発生した接続は、キャッシュ内で自動的に無効になります。TAFは、接続単位でネットワーク・レベルで動作するため、接続キャッシュに障害の発生を通知できません。

- イベントベース
高速接続フェイルオーバーは、Oracle RACイベント・メカニズムに基づいています。したがって、高速接続フェイルオーバーは効率的で、アクティブおよび非アクティブな接続の両方で障害をすばやく検出できます。

- ロード・バランシングのサポート
高速接続フェイルオーバーは、接続のUPイベント・ロード・バランシング、およびアクティブなOracle RACインスタンス間での実行時作業要求分散をサポートしています。

注意:
TAFと高速接続フェイルオーバーを同じアプリケーションで使用しないことをお薦めします。

28 透過的アプリケーション・フェイルオーバー

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

- 透過的アプリケーション・フェイルオーバーの概要

- フェイルオーバー・タイプ・イベント

- TAFコールバック

- Java TAFコールバック・インタフェース

透過的アプリケーション・フェイルオーバーの概要

透過的アプリケーション・フェイルオーバー(TAF)は、Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバの機能の1つです。この機能により、接続先のデータベース・インスタンスに障害が発生した場合でも、アプリケーションはデータベースに自動的に再接続できます。この場合、アクティブ・トランザクションはロールバックされます。

接続先インスタンスで障害が発生したり、このインスタンスがシャットダウンしたりすると、クライアント側の接続が無効になり、その接続を使用しようとしたコール元に例外が表示されます。TAFにより、アプリケーションは、事前に構成した2次インスタンスに透過的に再接続し、最初の元のインスタンスで確立したのと同じ接続を新たに作成します。つまり、この接続プロパティは、直前の接続のプロパティと同じです。接続がどのように切断されても関係ありません。

注意:
TAFは常にアクティブなので、設定する必要はありません。

フェイルオーバー・タイプ・イベント

OracleOCIFailoverインタフェースで発生する可能性があるフェイルオーバー・イベントは、次のとおりです。

- FO_SESSION
tnsnames.oraファイルCONNECT_DATAフラグのFAILOVER_MODE=SESSIONに相当します。この結果、サーバー側ではユーザー・セッションのみが再度認証され、一方OCIアプリケーションのオープン・カーソルは再実行する必要があります。

- FO_SELECT
tnsnames.oraファイルCONNECT_DATAフラグのFAILOVER_MODE=SELECTに相当します。サーバー側でユーザー・セッションが認証されるのみでなく、OCIのオープン・カーソルもフェッチを続行できます。これは、クライアント側のロジックで各オープン・カーソルのフェッチ状態が保持されることを意味します。

- FO_NONE
tnsnames.oraファイルCONNECT_DATAフラグのFAILOVER_MODE=NONEに相当します。これはデフォルトで、フェイルオーバー機能は使用されません。また、フェイルオーバーが実行されるのを明示的に禁止することにもなります。さらに、FO_TYPE_UNKNOWNは、OCIドライバから不正なフェイルオーバー型が戻されたことを意味します。

- FO_BEGIN
フェイルオーバーで失われた接続が検出され、フェイルオーバーが開始されることを意味します。

- FO_END
フェイルオーバーが正常に完了したことを意味します。

- FO_ABORT
フェイルオーバーが失敗し、再試行できないことを意味します。

- FO_REAUTH
ユーザー・ハンドルが再認証されたことを意味します。

- FO_ERROR
フェイルオーバーが一時的に失敗したが、アプリケーションでエラーを処理してフェイルオーバーを再試行できることを意味します。sleepメソッドを発行した後、値FO_RETRYを戻して再試行するのが、エラー処理の一般的な方法です。

- FO_RETRY
アプリケーションでフェイルオーバーを再試行することを意味します。

- FO_EVENT_UNKNOWN
不正なフェイルオーバー・イベントを意味します。

TAFコールバック

TAFコールバックは、1つのデータベース接続に障害が起きた場合に、別のデータベース接続にフェイルオーバーする際に使用されます。TAFコールバックは、フェイルオーバーが発生したときに登録されるコールバックです。コールバックは、フェイルオーバー中にイベントが発生したことをJDBCアプリケーションに通知するためにコールされます。アプリケーション側でもフェイルオーバーをある程度制御できます。

注意:
コールバックの設定はオプションです。

Java TAFコールバック・インタフェース

OracleOCIFailoverインタフェースには、次の型とイベントをサポートするcallbackFnメソッドが含まれます。

public interface OracleOCIFailover{

// Possible Failover Types
public static final int FO_SESSION = 1;
public static final int FO_SELECT  = 2;
public static final int FO_NONE  = 3;
public static final int;

// Possible Failover events registered with callback
public static final int FO_BEGIN   = 1;
public static final int FO_END     = 2;
public static final int FO_ABORT   = 3;
public static final int FO_REAUTH  = 4;
public static final int FO_ERROR  = 5;
public static final int FO_RETRY  = 6;
public static final int FO_EVENT_UNKNOWN = 7;

public int callbackFn (Connection conn,
Object ctxt, // ANy thing the user wants to save
int type, // One of the possible Failover Types
int event ); // One of the possible Failover Events

FO_ERRORイベントの処理

新しい接続にフェイルオーバーするときにエラーが発生した場合、JDBCアプリケーションはそのフェイルオーバーを再試行できます。一般に、アプリケーションは一度スリープ状態に入った後、コールバックでFO_RETRYを戻すことで、無限または一定の時間のみ再試行します。

FO_ABORTイベントの処理

登録されたコールバックは、FO_ERRORイベントが渡された場合、FO_ABORTイベントを戻す必要があります。

第VII部

トランザクション管理

第VII部では、Oracle Java Database Connectivity(JDBC)でのトランザクション管理について説明します。分散トランザクションのOracle JDBC実装についても説明します。

第VII部の構成は次のとおりです。

- 第29章「分散トランザクション」

29 分散トランザクション

この章では、分散トランザクションのOracle Java Database Connectivity(JDBC)実装について説明します。これは多フェーズ・トランザクションで、しばしば複数のデータベースを使用し、協調してコミットされる必要があります。Java固有でなく分散トランザクションの一般的な標準であるXAについての関連説明もあります。

内容は次のとおりです。

- 分散トランザクションの概要

- XAコンポーネント

- エラー処理と最適化

- 分散トランザクションの実装

- Oracle JDBCドライバのネイティブXA

分散トランザクションの詳細および一般情報は、Sun社のJDBC 2.0 Optional PackageおよびJava Transaction API(JTA)の仕様を参照してください。

分散トランザクションの概要

分散トランザクション(グローバル・トランザクションとも呼ばれる)は、複数の関連トランザクションの組合せで、協調して管理する必要があります。分散トランザクションを構成するトランザクションは、同じデータベース内に存在することもありますが、通常は異なるデータベースに存在し、多くの場合は異なる場所に存在します。分散トランザクションを構成する各トランザクションをトランザクション・ブランチと呼びます。

たとえば、分散トランザクションには、ある銀行のある口座から、別の銀行の口座への送金があります。両方の処理が正常に完了する保証がなければ、トランザクションはコミットできません。

JDBCでは、分散トランザクション機能が接続プーリング機能の最上位に構築されます。この分散トランザクション機能は、分散トランザクションのオープンXA標準にも基づいて構築されます。XAはX/Open標準の一部で、Java固有ではありません。

データベース・リソースに接続するには、JDBCを使用します。ただし、複数のデータベースに対するすべての変更を1回のトランザクションで更新するには、JTAグローバル・トランザクションでJDBC接続を使用する必要があります。トランザクションにデータベースSQL更新を含める処理は、データベース・リソースの参加と呼ばれます。

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

- 分散トランザクションのコンポーネントおよびシナリオ

- 分散トランザクションの概念

- ローカル・トランザクションとグローバル・トランザクションの切替え

- Oracle XAパッケージ

分散トランザクションのコンポーネントおよびシナリオ

この項の以降の部分を読むには、次のポイントを覚えておくと役に立ちます。

- 分散トランザクション・システムは、通常、標準JTA機能を実装するソフトウェア・コンポーネントなど、外部のトランザクション・マネージャを使用して、個々のトランザクションを協調させます。
多くのベンダーが、XA準拠のJTAモジュールを提供しています。たとえば、Oracleからは、Oracle9i Application ServerおよびOracle Application Server 10gでJTAが提供されています。

- XA機能は、通常、クライアント・アプリケーションから孤立しています。クライアント・アプリケーションではなく、アプリケーション・サーバーなど、中間層環境に実装されます。
多くの場合、アプリケーション・サーバーとトランザクション・マネージャはともに中間層に位置します。同時に、アプリケーション・コードの一部も中間層に位置します。

- この項の説明は、主に、中間層の開発者を対象にしています。

- 分散トランザクションの説明では、リソース・マネージャという用語が頻繁に使用されます。リソース・マネージャとは、単に、データまたはその他のリソースを管理するエンティティです。この章では、データベースの意味で使用されています。

注意:
JTA機能を使用するには、CLASSPATH環境変数にjta.jarが含まれている必要があります。このファイルは、ORACLE_HOME/jlibにあります。このファイルはJDBC製品に含まれています。Sun MicrosystemsのWebサイトからも入手できますが、Oracleドライバでテストされている、Oracleが提供するバージョンを使用することをお薦めします。

分散トランザクションの概念

XA機能を使用する場合、トランザクション・マネージャが、XAリソース・インスタンスを使用して各トランザクション・ブランチを準備し、協調させ、すべてのトランザクション・ブランチを適切にコミットまたはロールバックします。

XA機能には、次のキー・コンポーネントが含まれています。

- XAデータソース
接続プーリング・データソースおよびその他のデータソースの拡張機能で、概念および機能の面で似ています。

分散トランザクションで使用されるリソース・マネージャごとに1つのXAデータソース・インスタンスがあります。通常、XAデータソース・インスタンスは、中間層ソフトウェアで作成します。

XAデータソースは、XA接続を作成します。

- XA接続
プーリングされた接続の拡張機能で、概念および機能の面で似ています。XA接続は、物理的なデータベース接続をカプセル化します。個々の接続インスタンスは、これら物理接続の一時的なハンドルです。

1つのXA接続インスタンスは、1つのOracleセッションに対応します。ただし、1つのセッションは、プーリングされた接続インスタンスのように、複数の論理接続インスタンスで順に使用できます。

通常、XA接続インスタンスは、XAデータソース・インスタンスから、中間層ソフトウェアで取得します。分散トランザクションが、同じデータベースの複数セッションにかかわる場合、単一XAデータソース・インスタンスから複数のXA接続インスタンスを取得できます。

XA接続は、OracleXAResourceインスタンスおよびJDBC接続インスタンスを作成します。

- XAリソース
分散トランザクションのトランザクション・ブランチを協調させるために、トランザクション・マネージャで使用されます。

通常、OracleXAResourceインスタンスは、各XA接続インスタンスから1つずつ、中間層ソフトウェアで取得します。OracleXAResourceインスタンスとXA接続インスタンスの間には1対1の相関関係があります。同様に、OracleXAResourceインスタンスとOracleセッションの間には、1対1の相関関係があります。

一般的なシナリオでは、中間層コンポーネントがOracleXAResourceインスタンスをトランザクション・マネージャに渡します。トランザクション・マネージャは、これを使用して分散トランザクションを協調させます。

各OracleXAResourceインスタンスは1つのOracleセッションに対応するので、OracleXAResourceインスタンスに関連付けられたトランザクション・ブランチでアクティブになれるものは常に1つのみです。ただし、他のトランザクション・ブランチを保留しておくことはできます。

各OracleXAResourceインスタンスには、そのOracleXAResourceインスタンスに関連付けられたセッションで実行中のトランザクション・ブランチの操作を、開始、終了、準備、コミットまたはロールバックする機能があります。

準備処理は、2フェーズ・コミット操作の最初の処理です。トランザクション・マネージャは、各OracleXAResourceインスタンスにPREPAREを発行します。トランザクション・マネージャは、各トランザクション・ブランチの操作が正常に準備されたことを確認すると、各OracleXAResourceインスタンスにCOMMITを発行し、すべての変更をコミットします。

- トランザクションID
トランザクション・ブランチを識別するために使用されます。各トランザクションIDには、トランザクション・ブランチIDコンポーネントと分散トランザクションIDコンポーネントが含まれています。これにより、ブランチが分散トランザクションに関連付けられます。ある分散トランザクションに関連付けられたOracleXAResourceインスタンスにはすべて、同じ分散トランザクションIDコンポーネントが含まれているトランザクションIDが設定されます。

- OracleXAResource.ORATRANSLOOSE
トランザクションIDがxidの疎結合トランザクションを起動します。

ローカル・トランザクションとグローバル・トランザクションの切替え

アプリケーションは、ローカル・トランザクションとグローバル・トランザクションの間で接続を共有できます。また、アプリケーションは、ローカル・トランザクションとグローバル・トランザクションの間で接続を切り替えることもできます。

接続は必ず次のモードのいずれかです。

- NO_TXN
この接続をアクティブの状態で使用しているトランザクションはありません。

- LOCAL_TXN
自動コミットがオフまたは無効になっているローカル・トランザクションが、アクティブの状態でこの接続を使用しています。

- GLOBAL_TXN
グローバル・トランザクションが、アクティブの状態でこの接続を使用しています。

各接続では、その接続で実行されている操作によって、これらのモードが自動的に切り替わります。接続は、インスタンス化されたときは常にNO_TXNモードです。

注意:
各モードはOracle Databaseに関連付けられたJDBCドライバによって内部的に保持されます。

表29-1では、接続モードの推移のルールについて説明します。

表29-1 接続モードの推移

現在のモード

NO_TXNに切り替わるとき

LOCAL_TXNに切り替わるとき

GLOBAL_TXNに切り替わるとき

NO_TXN

N/A

自動コミット・モードがfalseで、Oracle Data Manipulation Language(DML)文が実行された場合

この接続を提供したXAconnectionから取得されたXAResourceでstartがコールされた場合

LOCAL_TXN

次のいずれかの場合

- Oracle Data Definition Language(DDL)文が実行された場合

- commitがコールされた場合

- rollbackがパラメータなしでコールされた場合

N/A

なし

GLOBAL_TXN

この接続でオープンしているグローバル・トランザクション内で、この接続を提供したXAconnectionから取得されたXAResourceでendがコールされた場合

なし

N/A

前述のルールのいずれにも該当しない場合、モードは変わりません。

操作に関するモードの制限

現在の接続モードによって、トランザクション内で有効な操作が制限されます。

- LOCAL_TXNモードの場合、アプリケーションはstart、prepare、commit、rollback、forgetまたはendをXAResourceでコールできません。これらを起動すると、XAExceptionが発生します。

- GLOBAL_TXNモードの場合、アプリケーションではcommit、rollback、rollback(Savepoint)、setAutoCommit(true)またはsetSavepointをjava.sql.Connectionでコールすることや、OracleSetSavepointまたはoracleRollbackをoracle.jdbc.OracleConnectionでコールすることはできません。これらを起動すると、SQLExceptionが発生します。

注意:
このモードに関する制限のエラー・チェックは、トランザクションとセーブポイントAPIに関する標準のエラー・チェックに追加されます。

Oracle XAパッケージ

Oracleからは、XA標準に従い分散トランザクション機能を実装するクラスを含む、次の3つのパッケージが提供されます。

- oracle.jdbc.xa

- oracle.jdbc.xa.client

- oracle.jdbc.xa.server

XAデータ・ソース、XA接続およびXAリソースのための各クラスは、clientパッケージとserverパッケージのどちらにもあります。それぞれの抽象クラスは、最上位レベルのパッケージにあります。OracleXidクラスとOracleXAExceptionクラスは最上位レベルのoracle.jdbc.xaパッケージにあります。それらの機能が、コードが実行される場所に依存しないからです。

中間層のシナリオでは、OracleXid、OracleXAExceptionおよびoracle.jdbc.xa.clientパッケージをインポートします。

ただし、XAコードをターゲットOracle Databaseで実行する場合は、oracle.jdbc.xa.clientパッケージのかわりに、oracle.jdbc.xa.serverパッケージをインポートします。

ターゲット・データベースの内部で実行するコードでリモート・データベースにもアクセスする必要がある場合は、どちらのパッケージもインポートしません。かわりに、clientパッケージから使用するクラス(リモート・データベースにアクセスするとき)またはserverパッケージから使用するクラス(ローカル・データベースにアクセスするとき)の名前を完全に修飾する必要があります。クラス名は、これらのパッケージで重複しています。

XAコンポーネント

この項では、XAコンポーネント、つまりJDBC標準で指定される標準XAインタフェースと、それを実装するOracleクラスについて説明します。内容は次のとおりです。

- XADatasourceインタフェースとOracle実装

- XAConnectionインタフェースとOracle実装

- XAResourceインタフェースとOracle実装

- OracleXAResourceメソッドの機能と入力パラメータ

- XidインタフェースとOracle実装

XADatasourceインタフェースとOracle実装

javax.sql.XADataSourceインタフェースはXA接続のためのファクトリで、XAデータ・ソースの標準機能の大枠を定めています。オーバーロードされたgetXAConnectionメソッドは、XA接続インスタンスを戻し、次のように、オプションでユーザー名とパスワードを入力に取ります。

public interface XADataSource
{
XAConnection getXAConnection() throws SQLException;
XAConnection getXAConnection(String user, String password)
throws SQLException;
...
}

Oracle JDBCは、XADataSourceインタフェースをOracleXADataSourceクラスで実装します。どちらも、oracle.jdbc.xa.clientパッケージおよびoracle.jdbc.xa.serverパッケージに含まれています。

OracleXADataSourceクラスは、OracleConnectionPoolDataSourceクラス(OracleDataSourceクラスの拡張)の拡張も行います。そのため、すべての接続プロパティも継承されます。

OracleXADataSourceクラスのgetXAConnectionメソッドは、XA接続インスタンスのOracle実装を戻します。このインスタンスは、OracleXAConnectionインスタンスです。

注意:
前述の非プーリング・データソースの場合と同じネーミング規則を使用して、XAデータソースをJava Naming Directory and Interface(JNDI)に登録できます。

関連項目:
高速接続フェイルオーバーの詳細は、『Oracle Universal Connection Pool for JDBC開発者ガイド』を参照してください。

XAConnectionインタフェースとOracle実装

XA接続インスタンスは、プーリングされた接続インスタンスと同様に、データベースへの物理接続をカプセル化します。このデータベースは、そのXA接続インスタンスを作成したXAデータソース・インスタンスの接続プロパティで指定されたデータベースです。

各XA接続インスタンスには、対応するOracleXAResourceインスタンスを作成する機能もあります。このインスタンスは、分散トランザクションを協調させるために使用されます。

XA接続インスタンスは、標準javax.sql.XAConnectionインタフェースを実装するクラスのインスタンスです。

public interface XAConnection extends PooledConnection
{
javax.jta.xa.XAResource getXAResource() throws SQLException;
}

すでに説明したとおり、XAConnectionインタフェースはjavax.sql.PooledConnectionインタフェースを拡張します。そのため、getConnection、close、addConnectionEventListenerおよびremoveConnectionEventListenerメソッドも継承されます。

Oracle JDBCは、XAConnectionインタフェースをOracleXAConnectionクラスで実装します。どちらも、oracle.jdbc.xa.clientパッケージおよびoracle.jdbc.xa.serverパッケージに含まれています。

OracleXAConnectionクラスは、OraclePooledConnectionクラスも拡張します。

OracleXAConnectionクラスのgetXAResourceメソッドは、OracleXAResourceインスタンスのOracle実装を戻します。これはOracleXAResourceインスタンスです。getConnectionメソッドは、OracleConnectionインスタンスを戻します。

XA接続インスタンスから戻されるJDBC接続インスタンスは、物理接続のカプセル化ではなく、物理接続への一時的なハンドルとして機能します。物理接続は、XA接続インスタンスでカプセル化されます。XAConnectionオブジェクトから取得された接続は、グローバル・トランザクションに加わるまでは通常の接続とまったく同じように動作します。グローバル・トランザクションに加わった時点で、自動コミット・ステータスがfalseに設定されます。グローバル・トランザクションが終了すると、自動コミット・ステータスはグローバル・トランザクション前の値に戻ります。XAConnectionから取得された接続でのデフォルトの自動コミット・ステータスは、Oracle Database 10gより前のすべてのリリースでは、falseです。Oracle Database 10gから、デフォルトのステータスはtrueです。

XA接続インスタンスgetConnectionメソッドは、コールされるたびに、デフォルトの動作を示す新しい接続インスタンスを戻します。また、以前の接続インスタンスで、残存していて、同じXA接続インスタンスによって戻されたものをすべてクローズします。ただし、新しい接続インスタンスをオープンする前に、以前の接続インスタンスはすべて明示的にクローズしておくことをお薦めします。

XA接続インスタンスのcloseメソッドをコールすると、データベースへの物理接続がクローズされます。これは、通常、中間層で実行します。

XAResourceインタフェースとOracle実装

トランザクション・マネージャはOracleXAResourceインスタンスを使用して、分散トランザクションを構成するすべてのトランザクション・ブランチを協調させます。

各OracleXAResourceインスタンスは、次の主要な機能を提供します。通常、トランザクション・マネージャから起動されます。

- 分散トランザクションと、このOracleXAResourceインスタンスを作成したXA接続インスタンスで動作するトランザクション・ブランチの、関連付けおよび関連付けの解除を行います。基本的には、分散トランザクションを物理接続またはXA接続インスタンスでカプセル化されたセッションに関連付けます。これは、トランザクションIDを使用して実行されます。

- 分散トランザクションの2フェーズ・コミット機能を実行します。すべてのトランザクション・ブランチで正常に処理されることが保証されるまで、その変更がどれか1つのトランザクション・ブランチでコミットされることはありません。

注意:

- XA接続インスタンスとOracleXAResourceインスタンスの間には常に1対1の相関関係があるので、関連付けられたXA接続インスタンスがクローズされると、OracleXAResourceインスタンスは暗黙的にクローズされます。

- あるOracleXAResourceインスタンスがトランザクションをオープンした場合、そのトランザクションは同じOracleXAResourceインスタンスによってクローズする必要があります。

OracleXAResourceインスタンスは、標準javax.transaction.xa.XAResourceインタフェースを実装するクラスのインスタンスです。Oracle JDBCは、XAResourceインタフェースをOracleXAResourceクラスとともに実装します。どちらも、oracle.jdbc.xa.clientパッケージおよびoracle.jdbc.xa.serverパッケージに含まれています。

Oracle JDBCドライバは、OracleXAConnectionクラスのgetXAResourceメソッドがコールされると、OracleXAResourceインスタンスを作成して戻します。OracleXAResourceインスタンスを、接続インスタンスおよびその接続によって実行されるトランザクション・ブランチに関連付けるのも、Oracle JDBCドライバの役割です。

このメソッドは、特定の接続およびその接続で実行されるトランザクション・ブランチにOracleXAResourceインスタンスを関連付けるときのメソッドです。

OracleXAResourceメソッドの機能と入力パラメータ

OracleXAResourceクラスには、トランザクション・ブランチを、関連付けられた分散トランザクションと協調させるためのメソッドがいくつかあります。この機能は、通常、2フェーズ・コミット操作で起動されます。

通常、トランザクション・マネージャが、アプリケーション・サーバーなどの中間層コンポーネントからOracleXAResourceインスタンスを受け取り、この機能を起動します。

これらのメソッドはそれぞれ、Xidインスタンスの形で、トランザクションIDを入力に取ります。それにはトランザクション・ブランチのIDコンポーネントと分散トランザクションのIDコンポーネントが含まれます。すべてのトランザクション・ブランチが一意のトランザクションIDを持っていますが、同一のグローバル・トランザクションに属するトランザクション・ブランチは、トランザクションIDの一部として、同じグローバル・トランザクション・コンポーネントを持ちます。

start

トランザクション・ブランチの処理を開始します。トランザクション・ブランチを分散トランザクションに関連付けます。

void start(Xid xid, int flags)

flagsパラメータには、次の値のうち1つ以上を設定する必要があります。

- XAResource.TMNOFLAGS
このXAリソース・インスタンスに関連付けられたセッションにおける後続の操作のための新しいトランザクション・ブランチが開始される箇所にフラグを設定します。このブランチはトランザクションID xidを持ちます。これは、トランザクション・マネージャによって作成されたOracleXidインスタンスです。これは、トランザクション・ブランチを適切な分散トランザクションにマップします。

- XAResource.TMJOIN
このXAリソース・インスタンスに関連付けられたセッションの後続の操作を、xidで指定した既存のトランザクション・ブランチに結合します。

- XAResource.TMRESUME
xidで指定したトランザクション・ブランチを再開します。

注意:
再開できるのは、前に保留されていたトランザクション・ブランチのみです。

- OracleXAResource.ORATMSERIALIZABLE
トランザクションIDがxidのシリアライズ可能なトランザクションを起動します。

- OracleXAResource.ORATMREADONLY
トランザクションIDがxidの読取り専用トランザクションを起動します。

- OracleXAResource.ORATMREADWRITE
トランザクションIDがxidの読取り/書込みトランザクションを起動します。

- OracleXAResource.ORATRANSLOOSE
トランザクションIDがxidの疎結合トランザクションを起動します。

TMNOFLAGS、TMJOIN、TMRESUME、ORATMSERIALIZABLE、ORATMREADONLYおよびORATMREADWRITE は、XAResourceインタフェースおよびOracleXAResourceクラスのstaticメンバーとして定義されています。ORATMSERIALIZABLE、ORATMREADONLYおよびORATMREADWRITEは、分離モード・フラグです。デフォルトの分離動作は、READ COMMITTEDです。

注意:

- TMRESUMEを指定してstartメソッドを使用するかわりに、トランザクション・マネージャでOracleXAResourceにキャストし、Oracle拡張機能resume(Xid xid)メソッドを使用することもできます。

- TMRESUMEを使用する場合は、start(xid, XAResource.TMRESUME | OracleXAResource.TMNOMIGRATE)の場合と同じように、TMNOMIGRATEも使用する必要があります。これにより、アプリケーションがエラー「ORA 1002: フェッチ順序が無効です。」を受け取らなくなります。

- 分離モード・フラグを不正確に使用すると、コードXAER_INVALの例外が発生します。さらに、グローバル・トランザクションを再開する場合、分離モード・フラグを使用することができません。これは、既存のトランザクションの分離レベルを設定できないためです。トランザクションを再開するときに分離モード・フラグを使用しようとすると、コードORA-24790の外部Oracle例外が発生します。

- エラー「ORA 1002: フェッチ順序が無効です。」の発生を防ぐには、startメソッドの一部としてTMNOMIGRATEフラグを含めます。たとえば、次のようになります。

start(xid, XAResource.TMSUSPEND | OracleXAResource.TMNOMIGRATE);

- OracleXAResourceで定義されているフラグはすべてOracle拡張機能です。これらのフラグを使用するトランザクション・マネージャの作成時には、この点を留意してください。

トランザクション・ブランチを起動するときに適切なトランザクションIDを作成するには、そのトランザクション・ブランチが属する分散トランザクションを、トランザクション・マネージャに指示する必要があります。このメカニズムは、中間層とトランザクション・マネージャの間で処理されます。

end

xidで指定されたトランザクション・ブランチの処理を終了します。トランザクション・ブランチと分散トランザクションの関連付けを解除します。

void end(Xid xid, int flags)

flagsパラメータには、次の値のうち1つを設定できます。

- XAResource.TMSUCCESS
このトランザクション・ブランチが正常であることを示します。

- XAResource.TMFAIL
このトランザクション・ブランチが異常であることを示します。

- XAResource.TMSUSPEND
xidで指定したトランザクション・ブランチを保留することを示します。トランザクション・ブランチを保留することにより、複数のトランザクション・ブランチを単一セッションで使用できます。ただし、常にアクティブにできるのは1つのみです。また、多くの場合、リソースの点から見て、2つのセッションを使用するよりもコストがかかります。

TMSUCCESS、TMFAILおよびTMSUSPENDは、XAResourceインタフェースおよびOracleXAResourceクラスの静的メンバーとして定義されています。

注意:

- TMSUSPENDを指定してendメソッドを使用するかわりに、トランザクション・マネージャでOracleXAResourceにキャストし、Oracle拡張機能suspend(Xid xid)メソッドを使用することもできます。

- トランザクションを保留するこのXA機能によって、単一JDBC接続で、各種トランザクションを切り替えることができます。分散トランザクション環境になく、XAクラスを必要としない場合でも、この機能を実現するためにXAクラスを使用できます。

- TMSUSPENDを使用する場合は、end(xid, XAResource.TMSUSPEND | OracleXAResource.TMNOMIGRATE)の場合と同じように、TMNOMIGRATEも使用する必要があります。これにより、アプリケーションがエラー「ORA 1002: フェッチ順序が無効です。」を受け取らなくなります。

- エラー「ORA 1002: フェッチ順序が無効です。」の発生を防ぐには、endメソッドの一部としてTMNOMIGRATEフラグを含めます。たとえば、次のようになります。

end(xid, XAResource.TMSUSPEND | OracleXAResource.TMNOMIGRATE);

- OracleXAResourceで定義されているフラグはすべてOracle拡張機能です。これらのフラグを使用するトランザクション・マネージャの場合は、この点を留意してください。

prepare

xidで指定されたトランザクション・ブランチで実行される変更の準備をします。これは、データベースへのアクセスと、変更の正常なコミットを保証する、2フェーズ・コミット操作の最初のフェーズです。

int prepare(Xid xid)

このメソッドでは、次の整数値を戻します。

- XAResource.XA_RDONLY
トランザクション・ブランチが、SELECT文など、読取り専用操作のみを実行する場合に戻されます。

- XAResource.XA_OK
トランザクション・ブランチが更新を実行する場合、すべて準備済で、エラーがなければ、この値が戻されます。

- N/A(戻り値なし)
トランザクション・ブランチが更新を実行する場合、そのうち1つでもエラーが発生すると、値は戻されません。この場合、XA例外がスローされます。

XA_RDONLYおよびXA_OKは、XAResourceインタフェースおよびOracleXAResourceクラスのstaticメンバーとして定義されています。

注意:

- prepareメソッドをコールする前に、必ずブランチのendメソッドをコールする必要があります。

- 分散トランザクションにあるトランザクション・ブランチが1つのみの場合、prepareメソッドをコールする必要はありません。準備なしに、OracleXAResourceのcommitメソッドをコールできます。

commit

xidで指定したトランザクション・ブランチで準備された変更をコミットします。これは2フェーズ・コミットの2番目のフェーズで、トランザクション・ブランチをすべて正常に準備できた場合のみ実行されます。

void commit(Xid xid, boolean onePhase)

onePhaseパラメータは、次のように設定します。

- true
トランザクション・ブランチをコミットするときに、2フェーズ・プロトコルでなく1フェーズ・プロトコルを使用します。これは、分散トランザクションにトランザクション・ブランチが1つのみ存在する場合に適しています。prepare手順は省略されます。

- false
トランザクション・ブランチをコミットするときに、2フェーズ・プロトコルを使用します。

rollback

xidで指定したトランザクション・ブランチで準備された変更をロールバックします。

void rollback(Xid xid)

forget

リソース・マネージャに、ヒューリスティックに完了したトランザクション・ブランクを破棄するよう通知します。

public void forget(Xid xid)

recover

トランザクション・マネージャは、リカバリ中にこのメソッドをコールして、現在準備中またはヒューリスティックに完了した状態のトランザクション・ブランチのリストを取得します。

public Xid[] recover(int flag)

注意:
TMSTARTRSCAN、TMENDRSCANまたはTMNOFLAGS以外の値をflagに使用すると、例外が発生します。そうでない場合、flagは無視されます。

リソース・マネージャは、現在準備中またはヒューリスティックに完了した状態のトランザクション・ブランチに対して、0(ゼロ)個以上のXidを戻します。操作中にエラーが発生した場合は、リソース・マネージャにより適切なXAExceptionが発行されます。

注意:
recoverメソッドは、Oracleデータベース・サーバーのDBA_PENDING_TRANSACTIONS上でSELECT権限、SYS.DBMS_XA上でEXECUTE権限が必要です。Oracle Database 11gリリース1(11.1)より前のデータベース・バージョンでは、Oracle Bug#5945463の修正を含むOracleパッチが利用できないか、個別のアプリケーション使用例にそのパッチを適用できない場合、recoverメソッドは、SYSBDBA権限も必要とします。SYSDBA権限を定期的に使用すると、セキュリティ上の問題があります。したがって、recoverメソッドを使用する必要がある場合、データベースをアップグレードするか、またはBug#5945463の修正を適用することを強くお薦めします。

isSameRM

2つのOracleXAResourceインスタンスが同じリソース・マネージャに対応しているかどうかを判断するには、一方のOracleXAResourceインスタンスから、入力としてもう一方のOracleXAResourceインスタンスを指定して、isSameRMメソッドをコールします。次の例では、xares1およびxares2はOracleXAResourceインスタンスとします。

boolean sameRM = xares1.isSameRM(xares2);

XidインタフェースとOracle実装

トランザクション・マネージャは各トランザクションIDインスタンスを作成し、分散トランザクションの各ブランチを協調させる際に使用します。各トランザクション・ブランチには一意のトランザクションIDが割り当てられます。これには次の情報が含まれます。

- フォーマット識別子
フォーマット識別子は、Javaトランザクション・マネージャを指定します。たとえば、フォーマット識別子ORCLがあります。このフィールドは、nullにできません。フォーマット識別子のサイズは4バイトです。

- グローバル・トランザクション識別子
分散トランザクションIDコンポーネントとも呼ばれます。グローバル・トランザクション識別子のサイズは64バイトです。

- ブランチ修飾子
トランザクション・ブランチIDコンポーネントとも呼ばれます。ブランチ修飾子のサイズは64バイトです。

64バイトのグローバル・トランザクション識別子の値は、同じ分散トランザクションに属するトランザクション・ブランチすべてのトランザクションIDで同一です。ただし、トランザクションIDの全体は、トランザクション・ブランチごとに一意です。

XAトランザクションIDインスタンスは、標準javax.transaction.xa.Xidインタフェースを実装するクラスのインスタンスです。このインタフェースは、X/Openトランザクション識別子XID構造体のJavaマッピングです。

Oracleでは、このインタフェースをoracle.jdbc.xaパッケージのOracleXidクラスに実装しています。OracleXidインスタンスは、トランザクション・マネージャでのみ使用されますが、アプリケーション・プログラムまたはアプリケーション・サーバーにとって透過的です。

注意:
Oracleでは、OracleXAResourceのコールにOracleXidを使用する必要はありません。かわりに、javax.transaction.xa.Xidインタフェースを実装するクラスを使用します。

トランザクション・マネージャでは、次のメソッドを使用して、OracleXidインスタンスを作成できます。

public OracleXid(int fId, byte gId[], byte bId[]) throws XAException

fIdは、フォーマット識別子を表す整数値です。gId[]は、グローバル・トランザクション識別子を表すバイト配列です。bId[]は、ブランチ修飾子を表すバイト配列です。

Xidインタフェースでは、次のgetterメソッドが指定されています。

- public int getFormatId()

- public byte[] getGlobalTransactionId()

- public type[] getBranchQualifier()

エラー処理と最適化

この項では、XA例外の機能とエラー処理およびXA実装でのOracle最適化について説明します。内容は次のとおりです。

- XAExceptionクラスとメソッド

- OracleエラーとXAエラーのマッピング

- XAエラー処理

- Oracle XA最適化

例外とエラー処理の説明には、標準XA例外クラスとOracle固有のXA例外クラスが含まれます。また、特定のXAエラー・コードおよびエラー処理の方法も含まれます。

XAExceptionクラスとメソッド

XAメソッドでは、一般例外やSQLExceptionsではなく、XA例外が発生します。XA例外は、標準クラスjavax.transaction.xa.XAExceptionまたはそのサブクラスのインスタンスです。

Oracle XAExceptionは、Oracleエラーの部分とXAエラーの部分で構成されています。Oracleには、標準javax.transaction.xa.XAExceptionクラスのoracle.jdbc.xa.OracleXAExceptionサブクラスが用意されています。OracleXAExceptionインスタンスは、次のコンストラクタの1つを使用して構成されます。

public OracleXAException()

public OracleXAException(int error)

エラー値は、Oracle SQLエラー値とXAエラー値を組み合せたエラー・コードです。Oracleエラー値とXAエラー値を組み合せる正確な方法は、JDBCドライバによって判断されます。

OracleXAExceptionクラスには、次のメソッドが含まれます。

- public int getOracleError()
このメソッドは、例外に含まれるOracle SQLエラー・コード(標準ORAエラー番号)を戻します。Oracle SQLエラーがなければ、0を戻します。

- public int getXAError()
このメソッドは、例外に含まれるXAエラー・コードを戻します。XAエラー値は、javax.transaction.xa.XAExceptionクラスで定義されています。

OracleエラーとXAエラーのマッピング

表29-2で示すように、OracleエラーはOracleXAExceptionインスタンスのXAエラーに対応しています。

表29-2 OracleとXAのエラー・マッピング

Oracleエラー・コード

XAエラー・コード

ORA 03113

XAException.XAER_RMFAIL

ORA 03114

XAException.XAER_RMFAIL

ORA 24756

XAException.XAER_NOTA

ORA 24764

XAException.XA_HEURCOM

ORA 24765

XAException.XA_HEURRB

ORA 24766

XAException.XA_HEURMIX

ORA 24767

XAException.XA_RDONLY

ORA 25351

XAException.XA_RETRY

その他のORAエラーすべて

XAException.XAER_RMERR

XAエラー処理

次の例では、OracleXAExceptionクラスを使用して、XA例外を処理します。

try {
...
...Perform XA operations...
...
} catch(OracleXAException oxae) {
int oraerr = oxae.getOracleError();
System.out.println("Error " + oraerr);
}
catch(XAException xae)
{...Process generic XA exception...}

XA操作によってOracle固有のXA例外が発生しなかった場合、このコードは一般XA例外の処理を行いません。

Oracle XA最適化

Oracle JDBCには、分散トランザクションの2つ以上のブランチが同じデータベース・インスタンスを使用する場合、つまり、これらのブランチに関連付けられたOracleXAResourceインスタンスが同じリソース・マネージャに関連付けられている場合、パフォーマンスを改善する機能があります。

このような場合、これらのOracleXAResourceインスタンスのうち1つのprepareメソッドのみがXA_OKを戻すか、または失敗します。残りは、更新が行われる場合でも、XA_RDONLYを戻します。これにより、トランザクション・マネージャは、すべてのトランザクション・ブランチを暗黙的に結合し、XA_OKを戻した(または失敗した)OracleXAResourceインスタンスによって、結合されたトランザクションをコミット(失敗した場合はロールバック)できます。

トランザクション・マネージャは、OracleXAResourceクラスのisSameRMメソッドを使用して、2つのOracleXAResourceインスタンスが同じリソース・マネージャを使用しているかどうかを判断できます。このようにして、XA_RDONLY戻り値の意味を解析できます。

分散トランザクションの実装

この項では、Oracle XA機能を使用して分散トランザクションを実装する方法の例を示します。この項の内容は次のとおりです。

- Oracle XAのインポートの概要

- OracleのXAコード・サンプル

Oracle XAのインポートの概要

Oracle XA機能を使用するには、次のパッケージをインポートする必要があります。

import oracle.jdbc.xa.OracleXid;
import oracle.jdbc.xa.OracleXAException;
import oracle.jdbc.pool.*;
import oracle.jdbc.xa.client.*;
import javax.transaction.xa.*;

oracle.jdbc.poolパッケージには、接続プーリング機能のクラスが含まれています。この一部には、XA関連クラスがサブクラスとして含まれています。

また、コードがOracle Databaseの内部で実行され、そのデータベースにアクセスしてSQL操作を行う場合は、oracle.jdbc.xa.clientではなく、oracle.jdbc.xa.serverをインポートする必要があります。

import oracle.jdbc.xa.server.*;

サーバー側Thinドライバを使用して、アプリケーションがXAトランザクションの一部として別のOracle Databaseにアクセスする必要がある場合は、コードで完全に修飾されたoracle.xa.clientクラスの名前を使用できます。

clientおよびserverパッケージには、それぞれのバージョンのOracleXADataSource、OracleXAConnectionおよびOracleXAResourceクラスがあります。これら3つのクラスの抽象バージョンは、最上位のoracle.jdbc.xaパッケージに含まれています。

OracleのXAコード・サンプル

このサンプルでは、異なるデータベースに対する2つのトランザクション・ブランチで、2フェーズ分散トランザクションを使用します。

簡単にするため、このサンプルでは、通常は中間層に置くコードと、通常はトランザクション・マネージャに置くコード(OracleXAResourceメソッドの起動や、トランザクションIDの作成など)を組み合せているので、注意してください。

短くするため、トランザクションID作成の指定およびSQL操作の実行は、ここでは示しません。完全な例は製品に付属しています。

このサンプルは、次の順序で実行します。

1. トランザクション・ブランチ1を開始します。

2. トランザクション・ブランチ2を開始します。

3. ブランチ1のDML操作を実行します。

4. ブランチ2のDML操作を実行します。

5. トランザクション・ブランチ1を終了します。

6. トランザクション・ブランチ2を終了します。

7. ブランチ1を準備します。

8. ブランチ2を準備します。

9. ブランチ1をコミットします。

10. ブランチ2をコミットします。

// You need to import the java.sql package to use JDBC
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
import oracle.jdbc.xa.OracleXid;
import oracle.jdbc.xa.OracleXAException;
import oracle.jdbc.xa.client.*;
import javax.transaction.xa.*;

class XA4
{
public static void main (String args [])
throws SQLException
{

try
{
String URL1 = "jdbc:oracle:oci:@";
// You can put a database name after the @ sign in the connection URL.
String URL2 ="jdbc:oracle:thin:@(description=(address=(host=dlsun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))";
// Create first DataSource and get connection
OracleDataSource ods1 = new OracleDataSource();
ods1.setURL(URL1);
ods1.setUser("scott");
ods1.setPassword("tiger");
Connection conna = ods1.getConnection();

// Create second DataSource and get connection
OracleDataSource ods2 = new OracleDataSource();
ods2.setURL(URL2);
ods2.setUser("scott");
ods2.setPassword("tiger");
Connection connb = ods2.getConnection();

// Prepare a statement to create the table
Statement stmta = conna.createStatement ();

// Prepare a statement to create the table
Statement stmtb = connb.createStatement ();

try
{
// Drop the test table
stmta.execute ("drop table my_table");
}
catch (SQLException e)
{
// Ignore an error here
}

try
{
// Create a test table
stmta.execute ("create table my_table (col1 int)");
}
catch (SQLException e)
{
// Ignore an error here too
}

try
{
// Drop the test table
stmtb.execute ("drop table my_tab");
}
catch (SQLException e)
{
// Ignore an error here
}

try
{
// Create a test table
stmtb.execute ("create table my_tab (col1 char(30))");
}
catch (SQLException e)
{
// Ignore an error here too
}

// Create XADataSource instances and set properties.
OracleXADataSource oxds1 = new OracleXADataSource();
oxds1.setURL("jdbc:oracle:oci:@");
oxds1.setUser("scott");
oxds1.setPassword("tiger");

OracleXADataSource oxds2 = new OracleXADataSource();

oxds2.setURL("jdbc:oracle:thin:@(description=(address=(host=dlsun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))");
oxds2.setUser("scott");
oxds2.setPassword("tiger");

// Get XA connections to the underlying data sources
XAConnection pc1  = oxds1.getXAConnection();
XAConnection pc2  = oxds2.getXAConnection();

// Get the physical connections
Connection conn1 = pc1.getConnection();
Connection conn2 = pc2.getConnection();

// Get the XA resources
XAResource oxar1 = pc1.getXAResource();
XAResource oxar2 = pc2.getXAResource();

// Create the Xids With the Same Global Ids
Xid xid1 = createXid(1);
Xid xid2 = createXid(2);

// Start the Resources
oxar1.start (xid1, XAResource.TMNOFLAGS);
oxar2.start (xid2, XAResource.TMNOFLAGS);

// Execute SQL operations with conn1 and conn2
doSomeWork1 (conn1);
doSomeWork2 (conn2);

// END both the branches -- IMPORTANT
oxar1.end(xid1, XAResource.TMSUCCESS);
oxar2.end(xid2, XAResource.TMSUCCESS);

// Prepare the RMs
int prp1 =  oxar1.prepare (xid1);
int prp2 =  oxar2.prepare (xid2);

System.out.println("Return value of prepare 1 is " + prp1);
System.out.println("Return value of prepare 2 is " + prp2);

boolean do_commit = true;

if (!((prp1 == XAResource.XA_OK) || (prp1 == XAResource.XA_RDONLY)))
do_commit = false;

if (!((prp2 == XAResource.XA_OK) || (prp2 == XAResource.XA_RDONLY)))
do_commit = false;

System.out.println("do_commit is " + do_commit);
System.out.println("Is oxar1 same as oxar2 ? " + oxar1.isSameRM(oxar2));

if (prp1 == XAResource.XA_OK)
if (do_commit)
oxar1.commit (xid1, false);
else
oxar1.rollback (xid1);

if (prp2 == XAResource.XA_OK)
if (do_commit)
oxar2.commit (xid2, false);
else
oxar2.rollback (xid2);

// Close connections
conn1.close();
conn1 = null;
conn2.close();
conn2 = null;

pc1.close();
pc1 = null;
pc2.close();
pc2 = null;

ResultSet rset = stmta.executeQuery ("select col1 from my_table");
while (rset.next())
System.out.println("Col1 is " + rset.getInt(1));

rset.close();
rset = null;

rset = stmtb.executeQuery ("select col1 from my_tab");
while (rset.next())
System.out.println("Col1 is " + rset.getString(1));

rset.close();
rset = null;

stmta.close();
stmta = null;
stmtb.close();
stmtb = null;

conna.close();
conna = null;
connb.close();
connb = null;

} catch (SQLException sqe)
{
sqe.printStackTrace();
} catch (XAException xae)
{
if (xae instanceof OracleXAException) {
System.out.println("XA Error is " +
((OracleXAException)xae).getXAError());
System.out.println("SQL Error is " +
((OracleXAException)xae).getOracleError());
}
}
}

static Xid createXid(int bids)
throws XAException
{...Create transaction IDs...}

private static void doSomeWork1 (Connection conn)
throws SQLException
{...Execute SQL operations...}

private static void doSomeWork2 (Connection conn)
throws SQLException
{...Execute SQL operations...}
}

Oracle JDBCドライバのネイティブXA

通常、XAコマンドは次の方法でサーバーに送信できます。

- 非ネイティブAPIの使用

- ネイティブAPIの使用

この2つの方法でサーバーにXAコマンドを送信する場合、パフォーマンスに大きな相違があります。非ネイティブAPIと比較して、ネイティブAPIを使用するほうが、高いパフォーマンスを達成できます。

Oracle Database 10gより前は、ThinネイティブのAPIが利用できなかったため、ThinドライバはネイティブでないAPIを使用してXAコマンドをサーバーに送信していました。ネイティブでないAPIはPL/SQLプロシージャを使用します。このため、次の短所があります。

- ワイヤ上で異なるメッセージが必要です。

- データベースとのラウンドトリップが増加します。

- オープン状態のカーソルが増加します。

- 文キャッシュの領域を占有することによって、文キャッシュを破損します。

さらに、非ネイティブAPIの実装がサーバー内にあります。したがって、XAコマンドを送信する際の問題を解決するために、サーバーのパッチが必要です。パッチを適用するとサーバーを再起動する必要があるので、大きな問題になります。

Oracle Database 10gから、ThinネイティブAPIを使用できるようになったため、デフォルトではこのAPIを使用してXAコマンドを送信します。ネイティブAPIは、非ネイティブAPIよりも処理が10倍高速です。

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

- OCIネイティブXA

- ThinネイティブXA

OCIネイティブXA

ネイティブXAは、OracleXADataSourceクラスのtnsEntryおよびnativeXAプロパティを使用して有効にします。

関連項目:
これらのプロパティの説明は、表8-2「Oracle拡張データソース・プロパティ」を参照してください。

注意:
現在のところ、OCI Native XAは、マルチスレッド環境では機能しません。OCIドライバは、OracleのC/XAライブラリを使用して分散トランザクションをサポートします。このため、グローバル・トランザクションを再開する前に、各スレッドごとにXAConnectionを取得する必要があります。

構成およびインストール

Sun SolarisシステムまたはLinuxシステムの場合、ネイティブXA機能を使用可能にするには、共有ライブラリlibheteroxa11.soおよびlibheteroxa11_g.soが必要です。ネイティブXA機能を正しく動作させるには、これらのライブラリをインストールして、Sun Solarisの検索パスで使用可能にする必要があります。

Microsoft Windowsシステムの場合、ネイティブXA機能を使用可能にするには、heteroxa11.dllおよびheteroxa11_g.dllファイルが必要です。ネイティブXA機能を正しく動作させるには、これらのファイルをインストールして、WindowsのDLLパスで使用可能にする必要があります。

注意:
_gという接尾辞が付いたライブラリは、デバッグ・ライブラリです。

例外処理

分散トランザクションでネイティブXA機能を使用する場合は、アプリケーションでOracleXAExceptionまたはOracleSQLExceptionをチェックするのではなく、単純にXAExceptionまたはSQLExceptionをチェックすることをお薦めします。

関連項目:
ネイティブXAメッセージのリストについては、ネイティブXAメッセージを参照してください。

注意:
標準のXAエラー・コードに対するSQLエラー・コードのマッピングは、ネイティブXA機能には適用されません。

ネイティブXAのコード・サンプル

次のコードは、ネイティブXA機能を使用可能にする方法を示します。

...
// Create a XADataSource instance
OracleXADataSource oxds = new OracleXADataSource();
oxds.setURL(url);

// Set the nativeXA property to use Native XA feature
oxds.setNativeXA(true);

// Set the tnsEntry property to an older DB as required
oxds.setTNSEntryName("ora805");
...

ThinネイティブXA

JDBC OCIドライバと同様に、JDBC ThinドライバもネイティブXAをサポートしています。ただし、JDBC ThinドライバはデフォルトでネイティブXAをサポートします。一方、JDBC OCIドライバの場合、ネイティブXAのサポートがデフォルトでは使用可能になりません。

次のようにXAデータソースでsetNativeXA(false)をコールすることで、ネイティブXAを無効にできます。

...
// Create a XADataSource instance
OracleXADataSource oxds = new OracleXADataSource();
...
// Disabling Native XA
oxds.setNativeXA(false);
...

たとえば、ネイティブXAコードの不具合に対する回避策として、ネイティブXAの無効化が必要になる場合があります。

第VIII部

管理性

第VIII部では、Oracle Java Database Connectivity(JDBC)ドライバのデータベース管理および診断機能のサポートについて説明します。

第VIIIの構成は次のとおりです。

- 第30章「データベース管理」

- 第31章「JDBCの診断機能」

- 第32章「JDBC DMS Metric」

30 データベース管理

Oracle Database 11gリリース1(11.1)以降、2つのJDBCメソッド、startupおよびshutdownがoracle.jdbc.OracleConnectionインタフェースに追加されており、これによりOracle Databaseインスタンスの起動と停止を実行できます。SQL*Plusからデータベース・インスタンスを起動または停止する方法と同様です。

これらのメソッドを使用するには、サーバーに対する専用接続が必要です。ディスパッチャを使用して共有サーバーに接続することはできません。

startupおよびshutdownメソッドを使用するには、SYSDBAまたはSYSOPERとして接続する必要があります。SYSDBAまたはSYSOPERとして、Oracle JDBCドライバ経由で接続するには、INTERNAL_LOGON接続プロパティに適切な値を設定する必要があります。

SYSDBA権限を使用し、JDBC Thinドライバ経由でログオンできるようにするには、パスワード・ファイルを使用するようにサーバーを構成しておく必要があります。たとえば、SYSDBA権限を使用し、JDBC Thinドライバ経由で接続するようにsystem/managerを構成するには、次の手順を実行します。

1. コマンドラインから次のように入力します。

orapwd file=$ORACLE_HOME/dbs/orapw entries=5
Enter password: password

2. SQL*Plusから、SYSDBAとしてデータベースに接続し、次のコマンドを実行します。

GRANT SYSDBA TO system;
PASSWORD system
Changing password for system
New password: password
Retype new password: password

3. init.oraを編集し、次の行を追加します。

REMOTE_LOGIN_PASSWORDFILE=EXCLUSIVE

4. データベース・インスタンスを再起動します。

JDBC OCIドライバの場合は、JDBC Thinドライバと違い、サーバー上のパスワード・ファイルを指定することなく、SYSDBAまたはSYSOPERとしてローカルに接続できます。

startupメソッドを使用してデータベース・インスタンスを起動するには、SYSDBAまたはSYSOPER権限を使用して、PRELIM_AUTHモード(データベースがダウンしているときに許可される唯一の接続モード)でデータベースに接続する必要があります。そのためには、接続プロパティであるPRELIM_AUTHをtrueに設定する必要があります。PRELIM_AUTHモードでは、ダウンしているデータベース・インスタンスの起動のみ実行できます。このモードでは、SQL文の実行はできません。次のコードは、ダウンしているデータベース・インスタンスを起動する方法を示しています。

OracleDataSource ds = new OracleDataSource();
Properties prop = new Properties();
prop.setProperty("user","sys");
prop.setProperty("password","manager");
prop.setProperty("internal_logon","sysdba");
prop.setProperty("prelim_auth","true");
ds.setConnectionProperties(prop);
ds.setURL("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=XYZ.com)(PORT=1521))"
+ "(CONNECT_DATA=(SERVICE_NAME=rdbms.devplmt.XYZ.com)))");
OracleConnection conn = (OracleConnection)ds.getConnection();
conn.startup(OracleConnection.DatabaseStartupMode.NO_RESTRICTION);
conn.close();

注意:
startupメソッドは、サーバーのパラメータ・ファイルを使用してデータベースを起動します。Oracle JDBCドライバは、クライアントのパラメータ・ファイルを使用したデータベースの起動はサポートしていません。

startupメソッドには、データベース起動オプションを指定するパラメータを指定できます。表30-1は、サポートされているデータベース起動オプションを示しています。これらのオプションは、oracle.jdbc.OracleConnection.DatabaseStartupModeクラスで定義されています。

表30-1 サポートされているデータベース起動オプション

オプション

説明

FORCE

新しいインスタンスを起動する前に、データベースで中断モードになっている現行インスタンスがある場合は停止します。

NO_RESTRICTION

アクセス制限なしでデータベースを起動します。

RESTRICT

データベースを起動し、データベース・アクセスを、CREATE SESSIONとRESTRICTED SESSIONの両方の権限を持つユーザー(通常はDBA)のみに許可します。

startupメソッドは、データベース・インスタンスを起動するのみです。データベース・インスタンスのマウントもオープンも実行しません。データベース・インスタンスをマウントおよびオープンするには、SYSDBAまたはSYSOPERとして、PRELIM_AUTH以外のモードで再接続する必要があります。次のコードは、データベース・インスタンスをマウントおよびオープンする方法を示しています。

OracleDataSource ds1 = new OracleDataSource();
Properties prop1 = new Properties();
prop1.setProperty("user","sys");
prop1.setProperty("password","manager");
prop1.setProperty("internal_logon","sysdba");
ds1.setConnectionProperties(prop1);
ds1.setURL(DB_URL);
OracleConnection conn1 = (OracleConnection)ds1.getConnection();
Statement stmt = conn1.createStatement();
stmt.executeUpdate("ALTER DATABASE MOUNT");
stmt.executeUpdate("ALTER DATABASE OPEN");

shutdownメソッドを使用すると、Oracle Databaseインスタンスを停止できます。このメソッドを使用するには、SYSDBAまたはSYSOPERとしてデータベースに接続する必要があります。次のコードは、データベース・インスタンスをシャットダウンする方法を示しています。

OracleDataSource ds2 = new OracleDataSource();
...
OracleConnection conn2 = (OracleConnection)ds2.getConnection();
conn2.shutdown(OracleConnection.DatabaseShutdownMode.IMMEDIATE);
Statement stmt1 = conn2.createStatement();
stmt1.executeUpdate("ALTER DATABASE CLOSE NORMAL");
stmt1.executeUpdate("ALTER DATABASE DISMOUNT");
stmt1.close();
conn2.shutdown(OracleConnection.DatabaseShutdownMode.FINAL);
conn2.close();

startupメソッドと同様、shutdownメソッドにもパラメータを指定できます。このパラメータには、データベースの停止に関するオプションを指定します。表30-2に、サポートされているデータベース停止オプションを示します。それらのオプションは、oracle.jdbc.OracleConnection.DatabaseShutdownModeクラスで定義されています。

表30-2 サポートされているデータベース停止オプション

オプション

説明

ABORT

現在のコールの完了も、データベースからのユーザーの切断も待ちません。

CONNECT

新しい接続を拒否し、既存の接続の終了を待ちます。

FINAL

データベースを停止します。

IMMEDIATE

現在のコールの完了も、データベースからのユーザーの切断も待ちません。

TRANSACTIONAL

新しいトランザクションを拒否し、アクティブなトランザクションの終了を待ちます。

TRANSACTIONAL_LOCAL

新しいローカル・トランザクションを拒否し、アクティブなローカル・トランザクションの終了を待ちます。

ABORTおよびFINAL以外の停止オプションの場合、データベースを実際に停止するには、FINALオプションを指定してshutdownメソッドを再度コールする必要があります。

注意:
shutdown(DatabaseShutdownMode.FINAL)メソッドをコールする場合は、事前に、CONNECT、TRANSACTIONAL、TRANSACTIONAL_LOCALまたはIMMEDIATEのいずれかのオプションを指定したshutdownメソッドをコールする必要があります。そうしないとコールがハングします。

データベースを停止するための標準的な方法は、次のとおりです。

1. 停止するための準備として、データベース内における以降の接続とトランザクションを禁止します。指定できる停止オプションは、CONNECT、TRANSACTIONAL、TRANSACTIONAL_LOCALまたはIMMEDIATEです。

2. 適切なALTER DATABASEコマンドをコールして、データベースをディスマウントおよびクローズします。

3. 最後に、FINALオプションを使用して停止を実行します。

データベースを可能なかぎり早く停止する必要があるような特殊な状況においては、ABORTオプションを使用することもできます。これは、SQL*PlusのSHUTDOWN ABORTに相当します。

完全な例

例30-1は、startupメソッドおよびshutdownメソッドの使用方法の例を示しています。

例30-1 データベースの起動と停止

import java.sql.Statement;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.pool.OracleDataSource;
/**
* To logon as sysdba, you need to create a password file for user "sys":
*   orapwd file=/path/orapw password=password entries=300
* and add the following setting in init.ora:
*   REMOTE_LOGIN_PASSWORDFILE=EXCLUSIVE
* then restart the database.
*/
public class DBStartup
{
static final String DB_URL = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=XYZ.com)(PORT=1521))"
+ "(CONNECT_DATA=(SERVICE_NAME=rdbms.devplmt.XYZ.com)))";

public static void main(String[] argv) throws Exception
{
// Starting up the database:
OracleDataSource ds = new OracleDataSource();
Properties prop = new Properties();
prop.setProperty("user","sys");
prop.setProperty("password","manager");
prop.setProperty("internal_logon","sysdba");
prop.setProperty("prelim_auth","true");
ds.setConnectionProperties(prop);
ds.setURL(DB_URL);
OracleConnection conn = (OracleConnection)ds.getConnection();
conn.startup(OracleConnection.DatabaseStartupMode.NO_RESTRICTION);
conn.close();

// Mounting and opening the database
OracleDataSource ds1 = new OracleDataSource();
Properties prop1 = new Properties();
prop1.setProperty("user","sys");
prop1.setProperty("password","manager");
prop1.setProperty("internal_logon","sysdba");
ds1.setConnectionProperties(prop1);
ds1.setURL(DB_URL);
OracleConnection conn1 = (OracleConnection)ds1.getConnection();
Statement stmt = conn1.createStatement();
stmt.executeUpdate("ALTER DATABASE MOUNT");
stmt.executeUpdate("ALTER DATABASE OPEN");
stmt.close();
conn1.close();

// Shutting down the database
OracleDataSource ds2 = new OracleDataSource();
Properties prop = new Properties();
prop.setProperty("user","sys");
prop.setProperty("password","manager");
prop.setProperty("internal_logon","sysdba");
ds2.setConnectionProperties(prop);
ds2.setURL(DB_URL);
OracleConnection conn2 = (OracleConnection)ds2.getConnection();
conn2.shutdown(OracleConnection.DatabaseShutdownMode.IMMEDIATE);
Statement stmt1 = conn2.createStatement();
stmt1.executeUpdate("ALTER DATABASE CLOSE NORMAL");
stmt1.executeUpdate("ALTER DATABASE DISMOUNT");
stmt1.close();
conn2.shutdown(OracleConnection.DatabaseShutdownMode.FINAL);
conn2.close();
}
}

31 JDBCの診断機能

Oracle Database 11gではJDBCドライバが拡張され、新しい診断機能が追加されると同時に、既存の診断機能も改良されました。これらの機能を使用すると、Oracle JDBCドライバを使用するアプリケーションの問題や、ドライバ自体の問題を診断することができます。また、Oracle JDBCドライバを使用してOracle DatabaseインスタンスにアクセスするJavaアプリケーションを開発、保守するために必要な労力を低減できます。

Oracle JDBCドライバには、ユーザーがJDBCアプリケーションの問題を識別および修正することを可能にする次の診断機能が用意されています。

- ロギング

- 診断能力管理

注意:
JDBCドライバの診断機能は、標準のjava.util.loggingフレームワークおよびjavax.management MBeanフレームワークに基づいています。これらの標準フレームワークについての情報はこの文書では扱いません。これらの標準フレームワークの詳細は、次を参照してください。

http://www.oracle.com/technetwork/java/index.html

ロギング

JDBCドライバのコードが実行されるときに発生するイベントの情報を記録します。イベントには、SQL例外などユーザーの目に触れるイベントも、内部JDBCメソッドの出入りなどの詳細JDBC内部イベントも含めることができます。ユーザーがこの機能を有効にすると、特定のイベントまたはすべてのイベントを記録することができます。

Oracle Database 11gより前は、JDBCドライバは、J2SE 2.0と3.0をサポートしていました。J2SEのこれらのバージョンには、java.util.loggingが含まれませんでした。このため、Oracle Database 11gより前のJDBCドライバ・リリースによって提供されるロギング機能は、java.util.loggingフレームワークと異なります。

Oracle Database 11gのJDBCドライバでは、J2SE 2.0と3.0はもうサポートされません。このため、JDBCドライバのロギング機能は、標準java.util.loggingパッケージをフル活用します。強化されたロギング・システムではログ・レベルが有効利用され、ユーザーはログ出力を関心のものに制限できます。特定のクラスの情報がより一貫して記録されるため、ログ・ファイルがわかりやすくなりました。

この機能では新しいAPIや構成ファイルは導入されません。既存の標準java.util.logging構成ファイルに新しいパラメータが追加されたのみです。これらのパラメータはjava.util.loggingの使用に不可欠なもので、既存のパラメータと同様に使用されます。

注意:
生成されたログの内容の正確性は保証されません。ログの内容は大部分、実装の詳細に依存します。実装の細部はリリースのたびに変更されるため、ログの正確な内容もリリースごとに変更される傾向があります。

JDBCロギングの有効化と使用

Javaアプリケーションのデバッグを開始する前に、JDBCロギングを有効にして、構成する必要があります。この項では、JDBCロギングを有効にして使用するために実行する必要がある手順を説明します。内容は次のとおりです。

- CLASSPATHの構成

- ロギングの有効化

- ロギングの構成

- ログ出力の使用

- 例

CLASSPATHの構成

JDBCドライバのそれぞれのバージョンに対応するいくつかのJARファイルが付属しています。最適化されたJARファイルにはロギング・コードが含まれていないため、使用時にログ出力が生成されません。ログ出力を取得するには、デバッグJARファイル(ojdbc5_g.jarやojdbc6_g.jarのようにファイル名に_gが付いています)を使用する必要があります。デバッグJARファイルはCLASSPATHに含まれている必要があります。

注意:
デバッグJARファイル、たとえばojdbc5_g.jarやojdbc6_g.jarがCLASSPATH内の唯一のOracle JDBC JARファイルであることを確認してください。

ロギングの有効化

ロギングを有効化する方法には次のようなものがあります。

- Javaシステム・プロパティの設定
oracle.jdbc.Traceシステム・プロパティを設定することによってロギングを有効にできます。

java -Doracle.jdbc.Trace=true ...

システム・プロパティの設定によりグローバル・ロギングを有効にできます。ロギングがアプリケーション全体に対して有効になります。アプリケーション全体をデバッグする場合、またはアプリケーションのソース・コードを変更しないか変更できない場合は、グローバル・ロギングを使用できます。

- プログラムによる有効化
ロギングをプログラム的に有効または無効にするには、次のようにします。

最初に、Diagnosability MBeanのObjectNameを取得します。ObjectNameは次のようになります。

com.oracle.jdbc:type=diagnosability,name=<loader>

loaderは、Oracle JDBCドライバをロードしたクラス・ローダー・インスタンスに基づいた一意の名前です。

注意:
ドライバは、1つの仮想マシンに複数回ロードできます。したがって、それぞれ一意の名前を持つ複数のMBeanが存在することになります。

次のとおりにコードを作成します。

ClassLoader l = oracle.jdbc.OracleDriver.getClassLoader();
String loader = l.getName() + "@" + l.hashCode();
// compute the ObjectName
javax.management.ObjectName name = new javax.management.ObjectName("com.oracle.jdbc:type=diagnosability,
name="+loader);

// get the MBean server
javax.management.MBeanServer mbs = java.lang.management.ManagementFactory.getPlatformMBeanServer();

// find out if logging is enabled or not
System.out.println("LoggingEnabled = " + mbs.getAttribute(name, "LoggingEnabled"));

// enable logging
mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled", true));

// disable logging
mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled", false));

注意:

- 同じクラス・ローダーでJDBCドライバが複数回数をロードすると、一意の名前を作成するために、MBeanが追加されるたびにl.hashCode()メソッドの値が増加します。どのMBeanがどのJDBCドライバ・インスタンスに関連付けられているかを識別することが難しくなる可能性があります。

- ロードされているJDBCドライバのインスタンスが1つしかない場合は、名前を*に設定します。

プログラムでロギングを有効および無効にすると、ログ出力の生成に必要なアプリケーションの部分を変更しやすくなります。

注意:
上のいずれかの方法を使用してロギングを有効にしても、重大なエラーの最小限のログが生成されるだけです。通常、それではあまり役に立ちません。より有用で詳細なログを生成するには、java.util.loggingを構成する必要があります。

ロギングの構成

有用で詳細なログを生成するには、java.util.loggingを構成する必要があります。これには、構成ファイルを使用する方法と、プログラム的に行う方法があります。

JDBCをインストールすると、サンプル構成ファイル、OracleLog.propertiesがdemoディレクトリに配置されます。そこにはjava.util.loggingの構成方法に関する基本情報や、最初に使用できるいくつかの初期設定が含まれています。このサンプル・ファイルをそのまま使用することも、ファイルを編集して使用することも、ファイルの名前を変更して使用することも、任意の名前を持つ完全に新しいファイルを作成することも可能です。

構成ファイルを使用するには、Javaランタイムにそれを認識させる必要があります。それには、システム・プロパティを設定します。たとえば、次のようになります。

java -Djava.util.logging.config.file=/jdbc/demo/OracleLog.properties.

ファイルはjava.util.loggingシステムによって読み取られます。このファイルはどこに配置してもかまいません。

java.util.logging.config.fileとoracle.jdbc.Traceは同時に使用できます。

java -Djava.util.logging.config.file=/jdbc/demo/OracleLog.properties -Doracle.jdbc.Trace=true

デフォルトのOracleLog.propertiesファイルを使用できます。希望する出力が得られる場合も、得られない場合もあります。独自の構成ファイルを作成して使用することもできます。次の手順に従ってください。

1. myConfig.propertiesという名前のファイルを作成します。どのような名前を使用してもかまいません。

2. そのファイルに次の行のテキストを挿入します。

.level=SEVERE
oracle.jdbc.level=INFO
oracle.jdbc.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

3. ファイルを保存します。

4. この構成ファイルを使用するようにシステム・プロパティを設定します。

java -Djava.util.logging.config.file=<filepath>/myConfig.properties ...

filepathは、myConfig.propertiesファイルを保存したフォルダのパスです。

また、java.util.loggingを構成して、ログ出力をファイルにダンプすることができます。そうする場合は、構成ファイルを次のように変更します。

.level=SEVERE
oracle.jdbc.level=INFO
oracle.jdbc.handlers=java.util.logging.FileHandler
java.util.logging.FileHandler.level=INFO
java.util.logging.FileHandler.pattern=jdbc.log
java.util.logging.FileHandler.count=1
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter

これにより、正確に同じログ出力が生成され、現在のディレクトリにjdbc.logという名前のファイルで保存されます。

レベル設定を変更することで、詳細度を制御することができます。定義されているレベルは、最も詳細度の低いものから最も高いものまで、次のようになります。

- OFF
ロギングをオフにします。

- SEVERE
SQLExceptionと内部エラーを記録します。

- WARNING
SQLWarningと、好ましくないが致命的ではない内部の状況を記録します。

- INFO
まれではあるが重要なイベントおよびエラーを記録します。生成されるログ・メッセージは比較的小量です。

- CONFIG
実行されるSQL文字列を記録します。

- FINE
すべてのパブリック・メソッドへの出入りが記録されるため、JDBC操作を詳細にトレースできます。生成されるログ・メッセージはかなり大量です。

- FINER
内部メソッドのコールを記録します。

- FINEST
大量の内部メソッドのコールを記録します。

- ALL
詳細をすべて記録します。ロギング詳細度が最も高いレベルです。

注意:
詳細度がFINEを超えるレベルでは、非常に大量のログが生成されます。

上で示された例で詳細の出力量を削減するには、java.util.logging.FileHandler.level設定をALLからINFOに変更します。

java.util.logging.FileHandler.level=INFO

oracle.jdbcログ出力のレベルを変更することは可能ですが、必要ありません。FileHandlerレベルを設定することで、ログ・ファイルにダンプされるログ・メッセージを制御できます。

ログ出力の使用

レベルを設定すると、JDBCからのすべてのロギング出力が減少します。しかし、コードのある部分からの出力は大量に必要ですが、他の部分からはほとんど必要ない場合があります。そうするには、ログ出力に関する深い理解が必要です。

ログ出力は、名前で定義されたツリー構造をなしています。ルート・ログ出力の名前は「」(空の文字列)です。構成ファイルの最初の行には、.level=SEVEREと記述されています。これは、ルート・ログ出力のレベル設定です。次の行はoracle.jdbc.level=INFOです。これは、oracle.jdbcという名前のログ出力のレベルを設定しています。oracle.jdbcログ出力は、ログ出力ツリーのメンバーです。その親はoracleという名前です。oracleログ出力の親がルート・ログ出力(空の文字列)です。

ロギング・メッセージは、特定のログ出力(たとえば、oracle.jdbc)に送信されます。メッセージがそのレベルのレベル・チェックに合格すると、メッセージは、そのレベルのハンドラ(存在する場合)と親ログ出力に渡されます。このため、ずっと見ていくと、oracle.logに送信されるログ・メッセージはそのログ出力のレベル、INFOに対して比較されます。レベルが同じか低い(詳細度が低い)場合、FileHandlerと親ログ出力(oracle)に送信されます。この場合も、レベルに対して確認されます。この例のような場合は、レベルが設定されていないため、親レベル(SEVERE)が使用されます。メッセージ・レベルが同じか低い場合は、ハンドラに渡され(存在しません)、親に送信されます。この場合は、ルート・ログ出力の親です。このようなツリー構造は、出力の量を減らす役には立ちませんでした。役に立つのは、JDBCドライバがいくつかのサブ・ログ出力を使用するということです。ログ・メッセージをいずれかのサブ・ログ出力に制限すると、出力が大幅に少なくなります。Oracle JDBCドライバによって使用されるログ出力は、次のとおりです。

- oracle.jdbc

- oracle.jdbc.driver

- oracle.jdbc.pool

- oracle.jdbc.rowset

- oracle.jdbc.xa

- oracle.sql

注意:
ドライバが使用するログ出力は、リリースによって異なることがあります。

例

oracle.sqlコンポーネントで発生していることを追跡し、残りのドライバに関する基本情報の一部を取得する場合を考えます。これは、ロギングのより複雑な使用方法です。configファイルのエントリを次に示します。

#
# set levels
#
.level=SEVERE
oracle.level=INFO
oracle.jdbc.driver.level=INFO
oracle.jdbc.pool.level=OFF
oracle.jdbc.util.level=OFF
oracle.sql.level=INFO
#
# configure handlers
#
oracle.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

構成ファイルのそれぞれの行で行われている処理を検討します。

.level=SEVERE

ルート・ログ出力のロギング・レベルをSEVEREに設定します。深刻な障害の場合を除き、他の、Oracleのものでないコンポーネントからのロギングを確認する必要はありません。このため、すべてのログ出力のデフォルト・レベルをSEVEREに設定します。明示的に設定された場合を除いて、各ログ出力はレベルを親から継承します。ルート・ログ出力のレベルをSEVEREに設定すると、あらためて設定したログ出力を除いて、他のすべてのログ出力が確実にそのレベルを継承するようにできます。

oracle.level=INFO

oracle.sqlとoracle.jdbc.driverログ出力の両方からログを出力します。共通の祖先はoracleです。このため、oracleログ出力のレベルをINFOに設定します。より低いレベルでは詳細度をより明示的に制御します。

oracle.jdbc.driver.level=INFO

ここでは、oracle.jdbc.driverからのSQL実行の表示のみが必要です。このため、レベルをINFOに設定します。これはかなり小量のレベルですが、このテストの処理内容を追跡するためには役立ちます。

oracle.jdbc.pool.level=OFF

このテストではDataSourceを使用しており、そのロギングすべてを表示する必要はありません。したがって、OFFにします。

oracle.jdbc.util.level=OFF

oracle.jdbc.utilパッケージからのロギングを表示する必要はありません。XAまたはRowsetを使用していた場合、それもオフにします。

oracle.sql.level=INFO

oracle.sqlで発生していることを表示します。このため、レベルをINFOに設定します。これにより、大量の詳細が出力されるのを回避しながら、パブリック・メソッドのコールについて多くの情報が得られます。

oracle.handlers=java.util.logging.ConsoleHandler

stderrに全内容をダンプします。テストを実行する場合、stderrをファイルにリダイレクトします。

java.util.logging.ConsoleHandler.level=INFO

System.errであるコンソールに全内容をダンプします。この場合、ハンドラでなくログ出力でフィルタリングしています。

java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

簡単でほぼ判読可能な形式を使用します。

この構成ファイルでテストを実行すると、oracle.sqlパッケージからは適度に詳細な情報を取得し、コア・ドライバ・コードからは少量の情報を取得します。他のコードからは何も取得しません。

XMLFormatterを使用して、Oracleサポートにログを送信することもできます。

カスタムjava.util.logging.Filterを実装および使用して、ログに書き込まれたデータをより詳細に制御できます。これは標準java.util.logging機能で、JSEのJavaDocに記述されています。カスタム・フィルタを使用すると、次のことが可能になります。

- マルチスレッド・アプリケーションのスレッドの取得(1つのみ)

- 長時間実行中のアプリケーションの断続的なエラーの取得

パフォーマンス、スケーラビリティおよびセキュリティに関する問題点

ロギング機能を使用すると、アプリケーションの追跡やデバッグ、および詳細ログ出力の生成が可能になりますが、パフォーマンス、スケーラビリティおよびセキュリティに関する問題が多少あります。

パフォーマンスとスケーラビリティの問題

ロギングは、パフォーマンスにかなり影響します。ただし、JDBCロギングは一般に本番システムでは有効ではありません。ロギングが無効の場合、パフォーマンスへの影響はありません。

スケーラビリティにも悪影響があります。ロギングには、多くの共有リソースへの保護アクセスが伴うため、結果として、スケーラビリティが大幅に低下します。これはjava.util.loggingフレームワークの問題です。ただし、通常の本番システムではJDBCロギングが有効ではないため、スケーラビリティへの影響はありません。

セキュリティ上の問題

フル・ロギングが有効な場合、すべての機密情報がほぼ確実にログ・ファイルに公開されてしまいます。これはロギング機能の内在的問題です。ただし、特定のJDBC JARファイルにのみ、JDBCロギング機能が含まれます。次のJARファイルにはフル・ロギングが含まれるため、機密を扱う環境での使用はお薦めしません。

- ojdbc5_g.jar

- ojdbc5dms_g.jar

- ojdbc6_g.jar

- ojdbc6dms_g.jar

次のJARファイルには、限定されたロギング機能が含まれます。

- ojdbc5dms.jar

- ojdbc6dms.jar

注意:
データベースのユーザー名とパスワードは、これらのJARファイルによって作成されたログ・ファイルには表示されません。ただし、SQL文、定義された値またはバインド値の一部である機密ユーザー・データは、これらのJARファイルのいずれかを使用して作成されたログに表示されます。

診断能力管理

JDBC診断能力管理機能には、MBean、oracle.jdbc.driver.OracleDiagnosabilityMBeanが導入されています。このMBeanを使用して、JDBCロギングの有効化および無効化が可能です。

関連項目:
OracleDiagnosabilityMBean APIの詳細は、次のWebサイトにあるOracle Javadocを参照してください。

http://download.oracle.com/otn/utilities_drivers/jdbc/111060/doc/javadoc/index.html

将来のリリースでは、このMBeanはJDBC内部関数に関する他の統計情報を提供するように拡張されます。

セキュリティ上の問題

この機能により、JDBCロギングを有効にできます。JDBCロギングを有効にするには、特別な権限は必要ありません。ただし、ロギングが有効になると、ログ出力を生成するために標準のJava権限LoggingPermissionが必要になります。この権限がない場合、ログを生成するすべてのJDBC処理でセキュリティ例外がスローされます。これは標準のJavaメカニズムです。

32 JDBC DMSメトリック

DMSメトリックはアプリケーション・コンポーネントのパフォーマンスを計測するために使用されます。

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

- JDBC DMSメトリックの概要

- 生成されるメトリックの種類の決定

- SQLTextメトリックの生成

- JMXを使用したDMSメトリックへのアクセス

注意:
エンドツーエンド・メトリックと呼ばれる別のメトリックがあります。エンドツーエンド・メトリックは、アプリケーション・コードへのエントリからJDBCを使用してデータベースまで(およびその逆)の、アプリケーション・アクティビティにタグ付けするために使用されます。
JDBCでは、次のエンドツーエンド・メトリックをサポートしています。

- Action

- ClientId

- ExecutionContextId

- Module

- State

前述のメトリックを使用する場合、oracle.jdbc.OracleConnectionインタフェースのsetEndToEndMetricsおよびgetEndToEndMetricsメソッドを使用できます。

Oracle Database 10gでは、Oracle Java Database Connectivity(JDBC)は、エンドツーエンド・メトリックをサポートしています。Oracle Database 11gリリース2(11.2)でエンドツーエンド・メトリックをアプリケーションが直接設定できるのは、DMS対応のJARを使用していない場合のみです。アプリケーションがDMS対応のJARファイルを使用している場合は、DMSを経由してのみエンドツーエンド・メトリックを設定できます。

エンドツーエンド・メトリックの詳細は、『Oracle Database JDBC Java API Reference』を参照してください。

注意:

アプリケーションがDMS対応のJARファイルを使用する場合、DMSメトリックを使用することを強くお薦めします。

JDBC DMSメトリックの概要

DMSメトリックを使用すると、アプリケーションおよびシステム開発者は、カスタマイズされたパフォーマンス・メトリックを特定のソフトウェア・コンポーネントのために測定およびエクスポートできます。DMSメトリックはすべて、次のDMS対応のJARファイルで使用できます。

- ojdbc5dms.jar

- ojdbc5dms_g.jar

- ojdbc6dms.jar

- ojdbc6dms_g.jar

他のJDBC JARファイルはいずれもDMSメトリックを生成しません。Oracle JDBC 11gリリースで生成されるメトリックは、Oracle JDBCの10.2、10.1、9.2以下のバージョンと異なり、以前のバージョンとの互換性を維持しようとしていません。互換性モードもありません。以前のバージョンのJDBCで生成されたDMSメトリックの正確な詳細に依存しているシステムは、Oracle JDBC 11gが生成したメトリックを処理すると、想定外の動作をすることがあります。これは設計どおりの動作で、変更できません。

文メトリックは、ある接続におけるすべての文について一括してレポートすることも、各文について個々にレポートすることもできます。DMSメトリックは、個別の文に関連するメトリックを除いて、すべて常時有効です。

注意:
SQLText文メトリックは、有効にも無効にもできます。デフォルトでは無効です。有効の場合、すべての文で有効です。

生成されるメトリックの種類の決定

一括メトリックと個別メトリックのどちらを使用するかを決定するために、JDBCはDMSConsoleセンサーの重みをチェックします。センサーの重みがDMSConsole.NORMAL以下の場合は、JDBCは一括文メトリックを生成します。センサーの重みがDMSConsole.NORMALを超えている場合は、JDBCは個別文メトリックを生成します。

プリコンパイルされたSQL文またはコール可能文を作成する場合、JDBCはDMSConsoleセンサーの重みをチェックし、文作成時点のセンサーの重みに応じて、メトリックが生成されます。文が作成された後でセンサーの重み値を変更しても、文により一括メトリックと個別メトリックが切り替えられることはありません。

注意:
文キャッシュが存在する場合、文は新たに作成されず、キャッシュから取得されるため、センサーの重みを変更しても変化がないように見えることがあります。

一括文メトリックと個別文メトリックの両方とも、生成される文メトリックのリストは1つのみです。これら2つのリストの唯一の相違は文の集計です。個別文メトリックが生成される場合、JDBCドライバによって作成された別個の文オブジェクトごとにそれぞれ1セットのメトリックが生成されます。一方、一括文メトリックが生成される場合、指定された接続によって作成されたすべての文が、同一の文メトリック・セットを使用します。

たとえば、'execute'フェーズ・イベントを検討してみましょう。個々の文メトリックが使用される場合、作成される各々の文は異なった'execute'フェーズのイベントを持ちます。このため、そのような文2つから、2つの異なる文に対応する実行統計を識別することが可能です。片方の実行時間が1秒で、もう一方の実行時間が3秒の場合、'execute'フェーズの異なる2つのイベント(合計時間と平均時間が1秒のイベントと、合計時間と平均時間が3秒のイベント)があることになります。しかし、一括文メトリックを使用すると、すべての文が、その接続に共通の、単一の'execute'フェーズのイベントを使用することになります。このため、同じ接続によって作成されるそのような2つの文から、2つの文の実行統計を識別することができなくなります。片方の実行時間が1秒で、もう一方の実行時間が3秒の場合、'execute'フェーズが共通のイベント(合計時間が4秒で平均時間が2秒)が報告されます。

SQLTextメトリックの生成

DMSのバージョンに応じて、SQLText文メトリックの生成を決定するメカニズムには次の2つがあります。

- DMS JARファイルの11gバージョンがclasspath環境変数に存在する場合、JDBCはDMS更新SQLテキスト・フラグをチェックします。このフラグがtrueの場合、SQLTextメトリックは更新されます。

- DMS JARファイルの11gバージョンがclasspath環境変数に存在しない場合、JDBCはDMSStatementMetrics接続プロパティの値を使用します。この文プロパティがtrueの場合、SQLTextメトリックは更新されます。この接続プロパティのデフォルト値はfalseです。

SQLTextメトリックが生成されるかどうかは、使用される文メトリックの種類、つまり個別文メトリックか一括文メトリックかには関係ありません。

JMXを使用したDMSメトリックへのアクセス

JMX(Java Management Extensions)は、アプリケーション、システム・オブジェクト、デバイス、サービス指向のネットワーク、JVM(Java仮想マシン)を管理および監視するツールを提供するJavaテクノロジです。JMXをサポートする管理アプリケーションを使用して、実行時に容易にDMSメトリックにアクセスできます。JMXを使用したDMSデータへのアクセスの詳細は、URL http://www.oracle.com/technology/products/ias/toplink/doc/1013/main/_html/optimiz004.htm#BEEFGGBEを参照してください。

第IX部

付録

第IX部では、Java Database Connectivity(JDBC)のリファレンス情報、JDBCアプリケーションのコーディングのヒント、JDBCエラー・メッセージおよびJDBCアプリケーションのトラブルシューティングについて説明します。

第IX部の構成は次のとおりです。

- 付録A「JDBCリファレンス情報」

- 付録B「Oracle RAC高速アプリケーション通知」

- 付録C「コーディングのヒント」

- 付録D「JDBCエラー・メッセージ」

- 付録E「トラブルシューティング」

このページのスクリプト内容はナビゲーション目的にのみ使用され、内容を変更するものではありません。

A JDBCリファレンス情報

この付録では、Java Database Connectivity(JDBC)リファレンス詳細情報について説明します。内容は次のとおりです。

- 有効なSQL-JDBCデータ型マッピング

- サポートされているSQLおよびPL/SQLデータ型

- 埋込みJDBCエスケープ構文

- Oracle JDBCの注意および制限事項

有効なSQL-JDBCデータ型マッピング

表11-1は、Oracle JDBCドライバでサポートされているJavaクラスとSQLデータ型とのデフォルトのマッピングです。表11-1のJDBC型コード、標準Java型およびSQLデータ型の列の内容と、表A-1の内容を比較してください。

表A-1は、特定のSQLデータ型のマッピング先として有効な、すべてのJava型のリストです。Oracle JDBCドライバでは、これらの非デフォルト・マッピングをサポートしています。たとえば、SQL CHARデータをoracle.sql.CHARオブジェクトとしてインスタンス化するには、getCHARメソッドを使用します。java.math.BigDecimalオブジェクトとしてインスタンス化するには、getBigDecimalメソッドを使用します。

注意:
oracle.sql.ORADataがイタリックで表示されているクラスでは、JPublisherで生成できます。

表A-1 有効なSQLデータ型-Javaクラス・マッピング

SQLデータ型

Java型

CHAR、VARCHAR2、LONG

java.lang.String

oracle.sql.CHAR

NUMBER

boolean

char

byte

short

int

long

float

double

java.lang.Byte

java.lang.Short

java.lang.Integer

java.lang.Long

java.lang.Float

java.lang.Double

java.math.BigDecimal

oracle.sql.NUMBER

BINARY_INTEGER

boolean

char

byte

short

int

long

BINARY_FLOAT

oracle.sql.BINARY_FLOAT

BINARY_DOUBLE

oracle.sql.BINARY_DOUBLE

DATE

oracle.sql.DATE

RAW

oracle.sql.RAW

BLOB

oracle.sql.BLOB

CLOB

oracle.sql.CLOB

BFILE

oracle.sql.BFILE

ROWID

oracle.sql.ROWID

TIMESTAMP

oracle.sql.TIMESTAMP

TIMESTAMPWITHTIMEZONE

oracle.sql.TIMESTAMPLTZ

TIMESTAMPWITHLOCALTIMEZONE

oracle.sql.TIMESTAMPLTZ

REFカーソル

java.sql.ResultSet

sqlj.runtime.ResultSetIterator

ユーザー定義の名前付き型、ADT

oracle.sql.STRUCT

opaque名前付き型

oracle.sql.OPAQUE

NESTED TABLEおよびVARRAY名前付き型

oracle.sql.ARRAY

名前付き型の参照

oracle.sql.REF

注意:

- UROWID型はサポートされていません。

- oracle.sql.Datumは抽象クラスです。oracle.sql.Datum型のパラメータに渡す値は、基礎となるSQL型に対応するJava型にする必要があります。同様に、戻り型oracle.sql.Datumのメソッドから戻される値は、基礎となるSQL型に対応するJava型にする必要があります。

サポートされているSQLおよびPL/SQLデータ型

この項の表は、SQLとPL/SQLのデータ型、およびOracle JDBCドライバがこれらのデータ型をサポートしているかどうかのリストです。表A-2は、SQLデータ型に対するOracle JDBCドライバのサポート状況のリストです。

表A-2 SQLデータ型に対するサポート

SQLデータ型

JDBCドライバによるサポート

BFILE

可

BLOB

可

CHAR

可

CLOB

可

DATE

可

NCHAR

不可脚注1

NCHAR VARYING

不可

NUMBER

可

NVARCHAR2

可脚注2

RAW

可

REF

可

ROWID

可

UROWID

不可

VARCHAR2

可

脚注1 NCHAR型が間接的にサポートされています。対応するjava.sql.Types型はありませんが、アプリケーションがformOfUse(NCHAR)メソッドをコールする場合には、これらの型にアクセスできます。

脚注2 JSE 6では、NVARCHAR2型が直接サポートされています。J2SE 5.0では、NVARCHAR2型が間接的にサポートされています。対応するjava.sql.Types型はありませんが、アプリケーションがformOfUse(NCHAR)メソッドをコールする場合には、これらの型にアクセスできます。

表A-3は、ANSIでサポートされているSQLデータ型に対するOracle JDBCドライバのサポート状況のリストです。

表A-3 ANSI-92 SQLデータ型に対するサポート

ANSIでサポートされているSQLデータ型

JDBCドライバによるサポート

CHARACTER

可

DEC

可

DECIMAL

可

DOUBLE PRECISION

可

FLOAT

可

INT

可

INTEGER

可

NATIONAL CHARACTER

不可

NATIONAL CHARACTER VARYING

不可

NATIONAL CHAR

可

NATIONAL CHAR VARYING

不可

NCHAR

可

NCHAR VARYING

不可

NUMERIC

可

REAL

可

SMALLINT

可

VARCHAR

可

表A-4は、SQLユーザー定義型に対するOracle JDBCドライバのサポート状況のリストです。

表A-4 SQLユーザー定義型に対するサポート

SQLユーザー定義型

JDBCドライバによるサポート

OPAQUE

可

参照型

可

オブジェクト型(JAVA_OBJECT)

可

NESTED TABLE型およびVARRAY型

可

表A-5は、PL/SQLデータ型に対するOracle JDBCドライバのサポート状況のリストです。PL/SQLデータ型には、次のカテゴリがあります。

- スカラー型

- スカラー文字列型(BOOLEANおよびDATEデータ型を含みます。)

- コンポジット型

- 参照型

- ラージ・オブジェクト(LOB)型

表A-5 PL/SQLデータ型に対するサポート

PL/SQLデータ型

JDBCドライバによるサポート

スカラー型

BINARY INTEGER

可

DEC

可

DECIMAL

可

DOUBLE PRECISION

可

FLOAT

可

INT

可

INTEGER

可

NATURAL

可

NATURALn

不可

NUMBER

可

NUMERIC

可

PLS_INTEGER

可

POSITIVE

可

POSITIVEn

不可

REAL

可

SIGNTYPE

可

SMALLINT

可

スカラー文字列型

CHAR

可

CHARACTER

可

LONG

可

LONG RAW

可

NCHAR

不可(「注意」を参照)

NVARCHAR2

不可(「注意」を参照)

RAW

可

ROWID

可

STRING

可

UROWID

不可

VARCHAR

可

VARCHAR2

可

BOOLEAN

可

DATE

可

コンポジット型

RECORD

不可

TABLE

不可

VARRAY

可

参照型

REF CURSOR型

可

オブジェクト参照型

可

LOB型

BFILE

可

BLOB

可

CLOB

可

NCLOB

可

注意:

- NATURAL、NATURALn、POSITIVE、POSITIVEnおよびSIGNTYPE型は、BINARY INTEGERのサブタイプです。

- DEC、DECIMAL、DOUBLE PRECISION、FLOAT、INT、INTEGER、NUMERIC、REALおよびSMALLINT型は、NUMBERのサブタイプです。

- NCHAR型およびNVARCHAR2型は間接的にサポートされています。対応するjava.sql.Types型はありませんが、アプリケーションがformOfUse(NCHAR)をコールする場合には、これらの型にアクセスできます。詳細は、「JDK 1.5のNCHAR、NVARCHAR2、NCLOBおよびdefaultNCharプロパティ」を参照してください。

埋込みJDBCエスケープ構文

Oracle JDBCドライバは、いくつかの埋込みJDBCエスケープ構文(中カッコで囲んで指定する構文)をサポートしています。現在のサポートは初歩的なものです。

注意:
JDBCエスケープ構文は、以前はSQL92構文またはSQL92エスケープ構文と呼ばれていました。

この項では、OracleのJDBCドライバによって提供される次の構文のサポートについて説明します。

- 時刻および日付リテラル

- スカラー関数

- LIKEエスケープ文字

- 外部結合

- ファンクション・コール構文

ドライバのサポートが制限されている場合、これらの項では、選択可能な回避策についても説明します。

エスケープ処理の無効化

JDBCエスケープ構文の処理はデフォルトで有効です。このため、SQLコードをデータベースに送信する前にJDBCドライバがエスケープ置換を実行します。ドライバが通常のOracle SQL構文(JDBCエスケープ構文処理より効率的です)を使用するようにするには、次の文を使用します。

stmt.setEscapeProcessing(false);

時刻および日付リテラル

日付、時刻およびタイムスタンプのリテラルに使用する構文は、データベースによって異なります。JDBCでは、特定の形式で記述された日付および時刻のみがサポートされています。この項では、SQL文内で使用する必要のある日付、時刻およびタイムスタンプのリテラルについて説明します。

日付リテラル

JDBCドライバは、次の形式で記述されたSQL文内の日付リテラルをサポートしています。

{d 'yyyy-mm-dd'}

yyyy-mm-ddは、年、月および日を表します。たとえば、次のようになります。

{d '1995-10-22'}

JDBCドライバは、このエスケープ句を等価のOracleの表現「22 OCT 1995」に置換します。

次のコードの抜粋には、SQL文内での日付リテラルの使用例が含まれています。

// Connect to the database
// You can put a database name after the @ sign in the connection URL.
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

// Create a Statement
Statement stmt = conn.createStatement ();

// Select the ename column from the emp table where the hiredate is Jan-23-1982
ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {d '1982-01-23'}");

// Iterate through the result and print the employee names
while (rset.next ())
System.out.println (rset.getString (1));

時刻リテラル

JDBCドライバは、次の形式で記述されたSQL文内の時刻リテラルをサポートしています。

{t 'hh:mm:ss'}

hh:mm:ssは、時、分および秒を表します。たとえば、次のようになります。

{t '05:10:45'}

JDBCドライバは、このエスケープ句を等価のOracleの表現「05:10:45」に置換します。

次のように時刻が指定されているとします。

{t '14:20:50'}

サーバーが24時間制のクロックを使用しているとすれば、等価のOracleの表現は「14:20:50」になります。

次のコードの抜粋には、SQL文内での時刻リテラルの使用例が含まれています。

ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {t '12:00:00'}");

タイムスタンプ・リテラル

JDBCドライバは、次の形式で記述されたSQL文内のタイムスタンプ・リテラルをサポートしています。

{ts 'yyyy-mm-dd hh:mm:ss.f...'}

yyyy-mm-dd hh:mm:ss.f...は、年、月、日、時、分および秒を表します。端数秒の部分(.f...)は省略できます。たとえば、{ts '1997-11-01 13:22:45'}は、Oracle形式ではNOV 01 1997 13:22:45と表されます。

次のコードの抜粋には、SQL文内でのタイムスタンプ・リテラルの使用例が含まれています。

ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {ts '1982-01-23 12:00:00'}");

Oracleオブジェクト型からSQL DATEデータ型へのマッピング

Oracle Database 8iおよびそれ以前のリリースではTIMESTAMPデータはサポートされませんでしたが、Oracle DATEデータには、SQL標準を拡張するtimeコンポーネントがありました。このため、JDBCドライバのOracle Database 8iおよびそれ以前のリリースは、oracle.sql.DATEをjava.sql.Timestampにマップしてtimeコンポーネントを維持していました。Oracle Database 9.0.1で初めてTIMESTAMPのサポートが含まれ、9i JDBCドライバがoracle.sql.DATEをjava.sql.Dateにマップするようになりました。このマッピングは不正確で、Oracle DATEデータのtimeコンポーネントを切り詰めました。この問題を解決するために、Oracle Database 11.1では、新しいフラグmapDateToTimestampが導入されました。このフラグのデフォルト値はtrueで、これは、ドライバがoracle.sql.DATEをデフォルトでjava.sql.Timestampに正しくマップすることを意味します。不正確でも10gとの互換性があるoracle.sql.DATEからjava.sql.Dateへのマッピングを使用する場合は、mapDateToTimestampフラグの値をfalseに設定します。

注意:

- Oracle Database 11gで、SQL問合せが使用するための索引がDATE列上にある場合、高速で正確な結果を入手するには、次のようにsetObjectメソッドを使用する必要があります。

Date d = parseIsoDate(val);
Timestamp t = new Timestamp(d.getTime());
stmt.setObject(pos, new oracle.sql.DATE(t, (Calendar)UTC_CAL.clone()));

これは、setDateメソッドを使用する場合はOracle DATEデータのtimeコンポーネントが失われ、setTimestampメソッドを使用する場合はDATE列上の索引が使用されないためです。

- oracle.sql.DATEからjava.sql.Dateへのマッピングの問題を解決するために、Oracle Database 9.2でフラグV8Compatibleが導入されました。このフラグのデフォルト値はfalseで、これによりjava.sql.DateデータへのOracle DATEデータのマッピングが可能になっています。ユーザーは、このフラグの値をtrueに設定することによって、Oracle DATEデータのtimeコンポーネントを維持できていました。このフラグは11gではサポートされません。それにより制御されるOracle Database 8iとの互換性がもうサポートされないためです。

スカラー関数

Oracle JDBCドライバでサポートしていないスカラー関数もあります。ドライバがサポートする関数を調べるには、Oracle固有のoracle.jdbc.OracleDatabaseMetaDataクラスおよび標準Javaのjava.sql.DatabaseMetadataインタフェースでサポートされている次のメソッドを使用します。

- getNumericFunctions()
ドライバによってサポートされている数値演算関数をカンマで区切られたリストで戻します。たとえば、「ABS, COS, SQRT」です。

- getStringFunctions()
ドライバによってサポートされている文字列関数をカンマで区切られたリストで戻します。たとえば、「ASCII, LOCATE」です。

- getSystemFunctions()
ドライバによってサポートされているシステム関数をカンマで区切られたリストで戻します。たとえば、「DATABASE, USER」です。

- getTimeDateFunctions()
ドライバによってサポートされている時刻および日付関数をカンマで区切られたリストで戻します。たとえば、「CURDATE, DAYOFYEAR, HOUR」です。

注意:
Oracle JDBCドライバは、ファンクション・キーワードのfnをサポートしています。

LIKEエスケープ文字

SQL LIKE句では、文字%および_には特別な意味があります。%は0文字以上の一致、_は1文字のみの一致に使用します。これらの文字を文字列内で文字どおりに使用する場合は、その前に特別なエスケープ文字を置きます。たとえば、アンパサンド&をエスケープ文字として使用する場合は、SQL文内では次のように識別させます。

Statement stmt = conn.createStatement ();

// Select the empno column from the emp table where the ename starts with '_'
ResultSet rset = stmt.executeQuery
("SELECT empno FROM emp WHERE ename LIKE '&_%' {ESCAPE '&'}");

// Iterate through the result and print the employee numbers
while (rset.next ())
System.out.println (rset.getString (1));

注意:
円記号(\)をエスケープ文字として使用する場合は、2回入力する(\\とする)必要があります。たとえば、次のようになります。

ResultSet rset = stmt.executeQuery("SELECT empno FROM emp
WHERE ename LIKE '\\_%' {escape '\\'}");

外部結合

OracleのJDBCドライバは、外部結合構文をサポートしていません。回避策は、Oracle外部結合構文を使用することです。

次の構文のかわりに、

Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("SELECT ename, dname
FROM {OJ dept LEFT OUTER JOIN emp ON dept.deptno = emp.deptno}
ORDER BY ename");

Oracle SQL構文を使用します。

Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("SELECT ename, dname
FROM emp b, dept a WHERE a.deptno = b.deptno(+)
ORDER BY ename");

ファンクション・コール構文

Oracle JDBCドライバは、次のプロシージャおよびファンクション・コール構文をサポートしています。

プロシージャ・コール:

{ call procedure_name (argument1, argument2,...) }

ファンクション・コール:

{ ? = call procedure_name (argument1, argument2,...) }

JDBCエスケープ構文からOracle SQL構文変換例

JDBCエスケープ構文をOracle SQL構文に変換する簡単なプログラムを記述できます。次のプログラムは、ファンクション・コール、日付リテラル、時刻リテラルおよびタイムスタンプ・リテラルのためのJDBCエスケープ構文を使用する文に対して、それに対応するOracle SQL構文を出力します。このプログラムでは、oracle.jdbc.OracleSqlクラスのparse()メソッドで変換します。

public class Foo
{
static oracle.jdbc.OracleDriver driver = new oracle.jdbc.OracleDriver();
public static void main (String args[]) throws Exception
{
show ("{call foo(?, ?)}");
show ("{? = call bar (?, ?)}");
show ("{d '1998-10-22'}");
show ("{t '16:22:34'}");
show ("{ts '1998-10-22 16:22:34'}");
}

public static void show (String s) throws Exception
{
System.out.println (s + " => " +
driver.processSqlEscapes(s));
}
}

対応するSQL構文の出力です。

{call foo(?, ?)} => BEGIN foo(:1, :2); END;
{? = call bar (?, ?)} => BEGIN :1 := bar (:2, :3); END;
{d '1998-10-22'} => TO_DATE ('1998-10-22', 'YYYY-MM-DD')
{t '16:22:34'} => TO_DATE ('16:22:34', 'HH24:MI:SS')
{ts '1998-10-22 16:22:34'} => TO_TIMESTAMP ('1998-10-22 16:22:34', 'YYYY-MM-DD
HH24:MI:SS.FF')

Oracle JDBCの注意および制限事項

Oracle JDBC実装には次の制限がありますが、すべて、ほとんど影響がないか、簡単な対処法があります。この項の内容は次のとおりです。

- CursorName

- JDBC外部結合エスケープ

- PL/SQL TABLE、BOOLEANおよびRECORD型

- IEEE 754浮動小数点との互換性

- DatabaseMetaDataコールへのCatalog引数

- SQLWarningクラス

- DDL文の実行

- 名前付きパラメータのバインド

CursorName

Oracle JDBCドライバは、get getCursorNameメソッドおよびsetCursorNameをサポートしません。それらをOracle構造にマップする便利な手段がないためです。かわりにROWIDを使用することをお薦めします。

関連項目:
ROWIDの使用および操作方法の詳細は、「Oracle ROWID型」を参照してください。

JDBC外部結合エスケープ

Oracle JDBCドライバでは、JDBC外部結合エスケープがサポートされません。かわりに、Oracle SQL構文で+を使用してください。

関連項目:
「埋込みJDBCエスケープ構文」

PL/SQL TABLE、BOOLEANおよびRECORD型

Oracle JDBCドライバでは、PL/SQLのRECORD、BOOLEAN、またはスカラー以外の要素型を持つ表の引数コールまたは戻り値をサポートできません。ただし、Oracle JDBCドライバはスカラー要素型のPL/SQL索引付き表をサポートします。

関連項目:
「PL/SQL索引付き表へのアクセス」

PL/SQLのRECORD、BOOLEANまたはスカラー以外の表型に対する対処法としては、JDBCによってサポートされている型としてデータを処理するコンテナ・プロシージャを作成します。たとえば、PL/SQLブーリアンを使用するストアド・プロシージャをラップするには、JDBCから文字または数値を取得し、BOOLEANとして元のプロシージャに渡すストアド・プロシージャを作成するか、出力パラメータの場合は、元のプロシージャからBOOLEAN引数を受け取り、CHARまたはNUMBERとしてJDBCに渡します。同様に、PL/SQLレコードを使用するストアド・プロシージャをラップするには、その個々のコンポーネントの形式で(CHAR、NUMBERなど)、または構造化オブジェクト型でレコードを処理するストアド・プロシージャを作成します。PL/SQL表を使用するストアド・プロシージャをラップするには、データをコンポーネントに分割するか、場合によってはOracleコレクション型を使用します。

関連項目:
BOOLEANの回避方法の例は、「PL/SQLストアド・プロシージャのブール型パラメータ」を参照してください。

IEEE 754浮動小数点との互換性

Oracle NUMBER型の算術演算は、浮動小数演算に関してIEEE 754規格に準拠していません。このため、Oracleによる演算結果とJavaによる演算結果に小さな誤差が生じることがあります。

Oracleでは、10進数演算と互換性のある形式で数値を格納し、小数点以下38桁までの精度を保証しています。このため、0(ゼロ)、無限大の負数、無限大の正数を正確に表現できます。各正数に対して、同じ絶対値の負数も表せます。

10-30から(1 – 10-38) * 10^126を38桁の完全精度で表せます。

DatabaseMetaDataコールへのCatalog引数

特定のDatabaseMetaDataメソッドによりcatalogパラメータが定義されます。このパラメータは、そのメソッドの選択条件の1つです。Oracleには複数カタログはありませんが、複数パッケージはあります。

関連項目:
Oracle JDBCドライバによるcatalog引数の処理方法の詳細は、「DatabaseMetaData TABLE_REMARKSレポート」を参照してください。

SQLWarningクラス

java.sql.SQLWarningクラスは、データベースのアクセス警告に関する情報を提供します。警告には、通常、警告の説明と警告を識別するコードが含まれます。警告は、オブジェクトが報告される原因になったメソッドに、通知なしで関連付けられます。Oracle JDBCドライバは、通常、SQLWarningをサポートしません。その例外として、スクロール可能な結果セットの操作ではSQL警告が生成されますが、SQLWarningインスタンスは、データベース内でなくクライアント上で作成されます。

関連項目:
「SQL例外の処理」

DDL文の実行

Data Definition Language (DDL)文は、Statementオブジェクトとともに実行する必要があります。PreparedStatementsオブジェクトまたはCallableStatementsオブジェクトを使用する場合、DDL文は初回の実行時にのみ有効です。SQL文が文キャッシュ内にある場合、これにより予期しない動作になる可能性があります。

名前付きパラメータのバインド

setXXXメソッドを使用する場合、名前によるバインドはサポートされていません。特定の環境下では、以前のバージョンのOracle JDBCドライバは、setXXXメソッドの使用時にも名前によって文変数をバインドできました。次の文では、名前付き変数EmpIdが整数314159とバインドされます。

PreparedStatement p = conn.prepareStatement
("SELECT name FROM emp WHERE id = :EmpId");
p.setInt(1, 314159);

set XXXメソッドを使用して名前を基準にバインドするこの機能は、JDBC仕様には含まれず、Oracleではサポートされません。JDBCドライバは、SQLExceptionをスローしたり、予想外の結果になったりすることがあります。Oracle Database 10g のJDBCドライバ以降、名前を基準としたバインドはsetXXXAtNameメソッドを使用してサポートされています。

関連項目:
「インタフェースoracle.jdbc.OracleCallableStatement」および「インタフェースoracle.jdbc.OraclePreparedStatement」

executeメソッドをコールするまで、ドライバはバインド値をコピーしません。このためexecuteメソッドをコールする前にバインド値を変更すると、バインド値が変更されることがあります。たとえば、次のコードを考えてみましょう。

PreparedStatement p;
.......
Date d = new Date(1181676033917L);
p.setDate(1, d);
d.setTime(0);
p.executeUpdate();

このコードはデータベースにDate(1181676033917L)でなくDate(0)を挿入します。これは、パフォーマンス上の理由でJDBCドライバ実装によりバインド値がコピーされていないためです。

B Oracle RAC高速アプリケーション通知

Oracle Database 11gリリース2(11.2)では、新しいセットのOracle RAC高速アプリケーション通知(FAN)イベントのAPIが導入されました。ユニバーサル接続プールまたはOracle JDBC接続キャッシュを使用しない場合にも、これらのAPIを使用するとOracle Databaseの高可用性(HA)機能を利用できます。これらのAPIはOracle JDBC APIの一部ではありません。

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

- Oracle RAC高速アプリケーション通知の概要

- Oracle RAC高速アプリケーション通知のインストールおよび構成

- Oracle RAC高速アプリケーション通知の使用

- 接続キャッシュの実装

この機能はOracle Notification System(ONS)メッセージ・トランスポート・メカニズムに依存しています。ONSを使用するには、システム、サーバーおよびクライアントで構成が必要です。

Oracle RAC高速アプリケーション通知を使用するには、simplefan.jarファイルがクラス・パスに存在するか、ons.jarファイルがクラス・パスに存在するか、Oracle Notification Services (ONS)クライアントがクライアント・システムにインストールされ、稼働している必要があります。

Oracle RAC高速アプリケーション通知の概要

Oracle RAC高速アプリケーション通知(FAN)機能は、コールバック・メカニズムによるFANイベントへのアクセス用に簡略化されたAPIを提供します。このメカニズムを使用すると、FANイベントが発生したときに、アプリケーション・コードでコールバックを受信できます。これらのAPIを、この付録ではOracle RAC FAN APIと呼んでいます。

Oracle RAC FAN APIは、Oracle Database HA機能をフルに活用して、反応のよいアプリケーションを開発するために役立つFANイベント通知です。Universal Connection Poolを使用するのでなく、独自の接続キャッシュを実装してFANイベントと連携するには、Oracle RAC高速アプリケーション通知を使用することをお薦めします。

注意:

- 独自の接続キャッシュを実装しない場合は、Universal Connection Poolを使用し、Oracle RAC高速アプリケーション通知の利点を他の多くの利点とあわせてすべて活用することをお薦めします。Universal Connection Poolingの詳細は、『Oracle Universal Connection Pool for JDBC開発者ガイド』を参照してください。

- Oracle Database 11gリリース2(11.2)から、暗黙的な接続キャッシュは非推奨となり、Universal Connection Pool(UCP)for JDBCがこれに置き換わりました。新しいアーキテクチャは、以前より強力でパフォーマンスも向上しているため、こちらを使用することをお薦めします。詳細は、次のリンクを参照してください。

http://www.oracle.com/technology/tech/java/sqlj_jdbc/index.html

Oracle RAC FAN APIを使用すると、Oracle RACによって送信されるFANイベント通知の、アプリケーション・コードによる受信と応答が可能になります。これは、コードが次の方法によりFANイベントに応答できるようにすることで実現します。

- Oracle RACサービスの停止イベント、サービスの起動イベントおよびノードの停止イベントのリスニング

- ロード・バランシング・アドバイザ・イベントのリスニングと、それらに対する応答

この機能により、FANイベントのサブセットが公開されます。これはOracle RACを実行しているクラスタによって送信される通知で、サブスクライバにクラスタ内の構成変更を通知します。サポートされているFANイベントは、次のとおりです。

- サービス起動
サービス起動イベントは、管理されているリソースが稼働中で使用可能であることを通知します。クラスタが管理するデータベース・サービスがアクティブになり、クラスタ内でインスタンスでの作業を受け入れるために使用可能になると、クラスタでは、サービス起動イベントを送信します。

- サービス停止
サービス停止イベントは、管理されているリソースが停止していてアクセスで使用できないことを通知します。サービス停止イベントには、次の2種類があります。

- サービスの特定のインスタンスが停止していることを通知するイベント。このインスタンスは作業を受け入れることができません。

- サービスのすべてのインスタンスが停止していることを通知するイベント。このサービスは作業を受け入れることができません。

サービスの最後のインスタンスが停止すると、サブスクライバは両方のイベントを受信します。これらのイベントは一緒に受信することもありますが、そうでない場合もあります。

- ノード停止
ノード停止イベントは、ホスト識別子で識別されるOracle RACノードが停止していて使用不可であることを通知します。クラスタは、ノードで作業を受け入れられなくなると、ノード停止イベントを送信します。

- ロード・バランシング・アドバイザ
ロード・バランシング・アドバイザ・イベントはロード・バランシング・アルゴリズムのためのメトリックを提供します。ロード・バランシング・アドバイザは、使用可能なノード間で推奨される作業分散についてサブスクライバに知らせるために定期的に送信されます。

注意:
独自の接続キャッシュを実装する場合にかぎり、Oracle RAC高速アプリケーション通知を使用することをお薦めします。それ以外の場合は、Universal Connection Poolを使用して、Oracle RAC高速アプリケーション通知の利点を、他の多くの利点ともども、すべて活用することをお薦めします。Universal Connection Poolingの詳細は、『Oracle Universal Connection Pool for JDBC開発者ガイド』を参照してください。

Oracle RAC高速アプリケーション通知のインストールおよび構成

Oracle RAC FAN APIをインストールするには、次の手順を実行します。

1. 次のリンクからsimplefan.jarファイルをダウンロードします。

http://www.oracle.com/technology/tech/java/sqlj_jdbc/index.html

2. simplefan.jarファイルをクラスパスに追加します。

3. Javaコードで次の操作を実行します。

1. getInstanceメソッドを使用して、FanManagerクラスのインスタンスを取得します。

2. FanManagerクラスのconfigureメソッドを使用して、イベント・デーモンを構成します。configureメソッドでは、次のプロパティを設定します。
onsNodes: このJava VMのONSランタイムが通信するONSデーモンのhost:portペアのカンマ区切りリスト。host:portペアのhostは、ONSデーモンを実行しているシステムのホスト名です。portは、そのデーモンのローカルのポート構成パラメータです。

onsWalletFile: ONSウォレット・ファイルのパス名。ウォレット・ファイルは、SSL証明書の格納にSSLが使用するローカルのウォレット・ファイルのパスです。ONSデーモンのウォレット・ファイル構成パラメータと同様です。

onsWalletPassword: ONSウォレット・ファイルにアクセスするためのパスワード。

Oracle RAC FAN APIの詳細は、『Oracle Database RAC FAN Events Java API Reference』を参照してください。

ONSの構成

Oracle RAC FANイベントのJava APIはOracle Notification System(ONS)サービスに依存しています。この項では、ONSを構成する方法について説明します。内容は次のとおりです。

- ONS構成ファイルの概要

- クライアント側ONSの構成

ONS構成ファイルの概要

ONS構成は、ONSの構成ファイルORACLE_HOME/opmn/conf/ons.configによって制御されます。このファイルは、ONSデーモンに動作方法を指示します。ons.config内の構成情報は、単純な名前と値のペアで定義されています。

ons.configファイルのパラメータには必須のものとオプションのものがあります。表B-1は必須のONS構成パラメータを示し、表B-2はオプションのONS構成パラメータを示します。

表B-1 必須のONS構成パラメータ

パラメータ

説明

localport

ローカル・クライアントと通信するために、ONSがローカル・ホスト・インタフェースでバインドするポート。

たとえば、localport=4100です。

remoteport

他のONSデーモンと通信するために、ONSがすべてのインタフェースでバインドするポート。

たとえば、remoteport=4200です。

nodes

通信相手である他のONSデーモンのリスト。ノード値は、ホスト名またはIPアドレスにポートを追加したもののカンマ区切りのリストとして指定します。提供するポート値は、各ONSインスタンスがリスニングしているリモート・ポートです。全ノードで同一のファイルを維持するために、現行のONSノードのhost:portをノード・リストに含めることも可能です。リストの読取り時には、これは無視されます。

たとえば、nodes=myhost.example.com:4200,123.123.123.123:4200です。

ノード行にリスト表示されているノードは、Oracle RACインスタンス内の個別のノードに対応します。ノードをリストに含めることにより、中間層ノードはOracle RACノードと確実に通信できます。最低1つの中間層ノードと、1つのOracle RACインスタンス内のノードを構成しないと、互いが認識されません。それぞれの側で最低1つのノードが互いを認識していると、すべてのノードが認識されます。各Oracle RACノードのONS構成ファイルでは、すべての単一クラスタおよび中間層ノードをリスト表示する必要はありません。特に、1つのONS構成ファイル・クラスタ・ノードが中間層を認識している場合、クラスタ内のすべてのノードが中間層を認識しています。

表B-2 オプションのONS構成パラメータ

パラメータ

説明

loglevel

ONSがログに記録するメッセージ・レベル。この値は、1(ログに記録されるメッセージ量は最小)から9(ログに記録されるメッセージ量は最大)までの整数値です。デフォルト値は3です。

たとえば、loglevel=3です。

logfile

ONSがメッセージのロギングに使用するログ・ファイル。ログ・ファイルのデフォルト値は$ORACLE_HOME/opmn/logs/ons.logです。

たとえば、logfile=/private/oraclehome/opmn/logs/myons.logです。

walletfile

Oracle Secure Sockets Layer(SSL)がSSL証明書の格納に使用するウォレット・ファイル。ONSでウォレット・ファイルが指定されると、他のONSインスタンスとの通信時にSSLを使用し、接続しようとするすべてのONSインスタンスからSSL証明書の認証を要求します。つまり、1つのONSインスタンスでSSLを有効にする場合、このインスタンスと接続されているすべてのインスタンスでも有効にする必要があります。この値は、ewallet.p12ファイルが存在するディレクトリを指すように設定します。

たとえば、walletfile=/private/oraclehome/opmn/conf/ssl.wlt/defaultです。

useocr

ONSがすべてのOracle RACノードおよびポート番号を、ONS構成ファイルでなくOracle Cluster Registry (OCR)に格納するかどうかを示す、サーバー側での使用のために予約されている値。useocr=onの場合、すべてのOracle RACノードおよびポート番号がOracle Cluster Registry (OCR)に格納されます。

このオプションは、クライアント側では使用しないでください。

ons.configファイルでは、ナンバー記号(#)で始まる行に空白行およびコメントを使用できます。

クライアント側ONSの構成

クライアント側のONSには、ORACLE_HOME/opmnを介してアクセスできます。クライアント側でONSを設定するには、次の2つの方法があります。

- リモートONS構成

関連項目:
「リモートONSサブスクリプション」

- クライアント側のONSデーモン

例B-1は、構成ファイルの例を示しています。

例B-1 ons.configサンプル・ファイルの例

# This is an example ons.config file
#
# The first three values are required
localport=4100
remoteport=4200
nodes=racnode1.example.com:4200,racnode2.example.com:4200

ONSを構成した後、onsctlコマンドでONSデーモンを起動します。ONSデーモンが常に稼働中であるかどうかは、ユーザーが確認する必要があります。

onsctlコマンドの使用

構成後、ORACLE_HOME/opmn/bin/onsctlを使用してONSデーモンの起動、停止、再構成および監視を行います。表B-3は、onsctlでサポートされているコマンドのサマリーを示しています。

表B-3 onsctlコマンド

コマンド

効果

出力

start

ONSデーモンを起動

onsctl: ons started

stop

ONSデーモンを停止

onsctl: shutting down ons daemon...

ping

ONSデーモンが稼働中であるかどうかを検証

ons is running ...

reconfig

ONSデーモンをシャットダウンせずにONS構成のリロードをトリガー

help

onsctlのヘルプ・サマリー・メッセージを出力

detailed

onsctlの詳細ヘルプ・メッセージを出力

関連項目:
『Oracle Real Application Clusters管理およびデプロイメント・ガイド』

Oracle RAC高速アプリケーション通知の使用

例B-2は、Oracle RAC高速アプリケーション通知のコードでの使用例を示しています。このコード例では、イベント・データを標準出力デバイスに出力します。

このコード例は、handleFanEventメソッドをオーバーロードして異なるFANイベント通知を引数として受け入れることによってOracle RAC FAN APIを使用する方法を示しています。また、次のイベント・データも示しています。

- FANイベント通知を送信するシステムの名前

- FANイベント通知のタイムスタンプ

- FANイベント通知のロード・ステータス

例B-2 Oracle RAC FAN APIを使用するサンプル・コードの例

...
...Properties props = new Properties();
props.putProperty(“serviceName”, “gl”);
FanSubscription sub = FanManager.getInstance().subscribe(props);
sub.addListener(new FanEventListener()) {
public void handleFanEvent(ServiceDownEvent event) {
try {
System.out.println(event.getTimestamp());
System.out.println(event.getServiceName());
System.out.println(event.getDatabaseUniqueName());
System.out.println(event.getReason());
ServiceMemberEvent me = se.getServiceMemberEvent();
if (me != null) {
System.out.println(me.getInstanceName());
System.out.println(me.getNodeName());
System.out.println(me.getServiceMemberStatus());
}
ServiceCompositeEvent ce = se.getServiceCompositeEvent();
if (ce != null) {
System.out.println(ce.getServiceCompositeStatus());
}
}
catch (Throwable t) {
// handle all exceptions and errors
t.printStackTrace(System.err);
}
}
public void handleFanEvent(NodeDownEvent event) {
try {
System.out.println(event.getTimestamp());
System.out.println(ne.getNodeName());
System.out.println(ne.getIncarnation());
}
catch (Throwable t) {
// handle all exceptions and errors
t.printStackTrace(System.err);
}
}
public void handleFanEvent(LoadAdvisoryEvent event) {
try {
System.out.println(event.getTimestamp());
System.out.println(le.getServiceName());
System.out.println(le.getDatabaseUniqueName());
System.out.println(le.getInstanceName());
System.out.println(le.getPercent());
System.out.println(le.getServiceQuality());
System.out.println(le.getLoadStatus());
}
catch (Throwable t) {
// handle all exceptions and errors
t.printStackTrace(System.err);
}
}
});

接続キャッシュの実装

Oracle RAC FAN APIを使用するには、独自の接続キャッシュを実装する必要があります。次の点を検討してから、Oracle RAC FAN APIを使用するために接続キャッシュを実装します。

- Oracle RAC FAN APIでは、FANイベントの最小サブセットを提供します。

- Oracle RAC FAN APIは、ONSイベントのみサポートします。対応するスーパークラスタ・イベントをアプリケーションでサポートする場合、サブスクリプション・プロパティへの追加が必要になることがあります。

- Oracle RAC FAN APIによって、アプリケーション・コードがFANイベントを送信できるようにはなりません。

C コーディングのヒント

この付録では、Java Database Connectivity(JDBC)アプリケーションまたはアプレットの最適化の方法について説明します。内容は次のとおりです。

- JDBCとマルチスレッド

- パフォーマンスの最適化

- トランザクション分離レベルとアクセス・モード

JDBCとマルチスレッド

Oracle JDBCドライバは、Javaマルチスレッドを使用するアプリケーションを完全にサポートし、それに対応するように最適化されています。接続キャッシュによって提供されるアクセスなど、接続に対する制御されたシリアル・アクセスが必要であり、そのようなアクセス方法をお薦めします。ただし、複数スレッド間でのデータベース接続の共有はお薦めしません。複数のスレッドが1つの接続に同時にアクセスできないようにしてください。複数のスレッドで接続を共有する必要がある場合は、規則的な使用開始/使用終了の方法を使用してください。

パフォーマンスの最適化

次の機能を使用すると、JDBCプログラムのパフォーマンスを大幅に向上させることができます。

- 自動コミット・モードの無効化

- 標準フェッチ・サイズとOracle行プリフェッチ

- 標準バッチ更新とOracleバッチ更新

- 文キャッシュ

自動コミット・モードの無効化

自動コミット・モードは、SQL操作を実行するたびに自動的にCOMMIT操作を発行するかどうかを、データベースに対して指示します。自動コミット・モードにすると、異なるバインド変数で同じ文を繰り返すような場合などに、時間と処理能力の面で大きな負荷がかかる場合があります。

デフォルトでは、新規の接続オブジェクトは自動コミット・モードが有効になります。ただし、接続オブジェクトjava.sql.Conectionまたはoracle.jdbc.OracleConnectionのどちらかのsetAutoCommitメソッドで自動コミット・モードを無効にできます。

自動コミット・モードでは、文が完了した時点または次の実行が発生した時点のうち、どちらか早い方でCOMMIT操作が発生します。ResultSetオブジェクトを戻す文の場合は、結果セットの最後の行が取り出されたとき、または結果セットがクローズしたときに文が完了します。より複雑なケースでは、1つの文で出力パラメータ値や複数の結果が返されることがあります。この場合、すべての結果および出力パラメータ値が取り出された時点でCOMMITが発生します。

setAutoCommit(false)をコールして自動コミット・モードを無効にした場合、接続オブジェクトのcommitまたはrollbackメソッドを使用して、操作のグループを手動でコミットまたはロールバックする必要があります。

例

次に、ドライバをロードしてデータベースに接続する例を示します。新しい接続はデフォルトで自動コミット・モードが有効になるので、この例では自動コミットを無効にする方法を示します。この例では、connはConnectionオブジェクトを、stmtはStatementオブジェクトを表します。

// Connect to the database
// You can put a database host name after the @ sign in the connection URL.
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();

// It's faster when auto commit is off
conn.setAutoCommit (false);

// Create a Statement
Statement stmt = conn.createStatement ();
...

標準フェッチ・サイズとOracle行プリフェッチ

Oracle JDBC接続オブジェクトや文オブジェクトでは、データベースにアクセスするたびにクライアントにプリフェッチする行数を指定できますが、結果セットは問合せ時に設定されます。接続オブジェクトに値を設定して、その接続で作成される各々の文に適用することも、任意の個別の文オブジェクト内でその値をオーバーライドすることもできます。接続オブジェクトのデフォルト値は、10です。クライアントにデータをプリフェッチすると、サーバーへのラウンドトリップの回数を減らすことができます。

JDBC 2.0では、同様かつさらに柔軟に、文オブジェクトにも(後続の問合せに影響)、結果セット・オブジェクトにも(行の再フェッチに影響)、1回のラウンドトリップでフェッチする行の数を指定できます。デフォルトでは、その結果セットを作成した文オブジェクトの値が、結果セットで使用されます。JDBC 2.0フェッチ・サイズを設定しないと、Oracle接続行プリフェッチ値がデフォルトとして使用されます。

関連項目:
「フェッチ・サイズ」

標準バッチ更新とOracleバッチ更新

Oracle JDBCドライバでは、プリコンパイルされたSQL文のINSERT、DELETEおよびUPDATEの各操作をクライアントに蓄積し、サーバーに一括送信することができます。この機能により、サーバーへのラウンドトリップの回数が低下します。プリセットされたバッチ値に到達すると、通常は暗黙的にバッチを処理するOracleバッチ更新を使用することも、バッチが明示的に処理される標準バッチ更新を使用することもできます。

注意:
バッチ・サイズを100以下の範囲に保つことをお薦めします。バッチが大きくなると、パフォーマンスはほとんど、またはまったく向上せず、実際には、大きなバッチを処理するために必要なクライアント・リソースのために、パフォーマンスが低下する可能性があります。

関連項目:
「バッチ更新」

文キャッシュ

文キャッシュにより、繰り返しコールされるループやメソッドなどで何度も使用する実行文がキャッシュされるため、パフォーマンスが向上します。アプリケーションでは、特定の物理接続に関連付けられている文をキャッシュするために文キャッシュを使用します。文キャッシュを有効にすると、closeメソッドをコールするときに文オブジェクトがキャッシュされます。物理接続ごとに独自のキャッシュがあるため、複数の物理接続に対して文キャッシュを有効にすると複数のキャッシュが存在することになります。

注意:
Oracle JDBCドライバは、Oracle文キャッシュで使用するために最適化されています。Oracle文キャッシュ(暗黙的または明示的)を使用することを強くお薦めします。

接続キャッシュで文キャッシュを有効にすると、基礎となる物理接続で有効な文キャッシュが論理接続で利用されます。接続キャッシュによって保持されている論理接続で文キャッシュを有効にしようとすると、例外が発生します。

関連項目:
第20章「文キャッシュと結果セット・キャッシュ」

組込みSQL型とJava型間のマッピング

SQL組込み型とはNUMBER、CHARなど、システム定義の名前を持つ型のことで、ユーザー定義の名前を持つ、Oracleオブジェクト、varrayおよびネストされた表型とは異なります。組込みSQL型のデータにアクセスするJDBCプログラムでは、プログラム・コンテキストによりSQLデータの変換先Java型が決定されるため、型変換はすべて一意です。

数値データにアクセスする最も効率的な方法は、int、float、longおよびdoubleなどのプリミティブJava型としてアクセスする方法です。ただし、これらの型の範囲は、SQL NUMBERデータ型の値の範囲と正確には一致しません。このため、一部の情報が失われる可能性があります。値の範囲全体で絶対的な精度が必要である場合は、BigDecimal型を使用します。

文字データはすべて、JavaのUCS2キャラクタ・セットに変換されます。文字データにアクセスする最も効率的な方法は、java.lang.Stringとしてアクセスする方法です。最も問題となるのは、データベース・キャラクタ・セットの2つ以上の文字が1つのUCS2キャラクタにマップされる場合に、情報が失われる可能性があることです。Oracle Database 11gでは、キャラクタ・セットのすべての文字がUCS2キャラクタ・セットの文字にマップされます。ただし、一部の文字はサロゲート・ペアにマップされます。

トランザクション分離レベルとアクセス・モード

読取り専用接続は、Oracle JDBCドライバではサポートされていますが、Oracleサーバーではサポートされていません。

トランザクションの場合、Oracleサーバーでサポートしているトランザクション分離レベルはTRANSACTION_READ_COMMITTEDおよびTRANSACTION_SERIALIZABLEのみです。デフォルトはTRANSACTION_READ_COMMITTEDです。レベルの取出しおよび設定を行うには、oracle.jdbc.OracleConnectionクラスの次のメソッドを使用します。

- getTransactionIsolation: この接続の現行トランザクション分離レベルを取得します。

- setTransactionIsolation: TRANSACTION_*値の1つを使用してトランザクション分離レベルを変更します。

D JDBCエラー・メッセージ

この付録では、Java Database Connectivity(JDBC)エラー・メッセージの一般構造について説明し、Oracle JDBCドライバによって戻されることがある一般JDBCエラー・メッセージとTTCエラー・メッセージのリストを示します。この付録の内容は次のとおりです。

- JDBCエラー・メッセージの一般構造

- 一般JDBCメッセージ

- ネイティブXAメッセージ

- TTCメッセージ

各メッセージ・リストは、まずORA番号順、次に五十音順にソートされています。

関連項目:
「SQL例外の処理」

JDBCエラー・メッセージの一般構造

一般的なJDBCエラー・メッセージ構造では、次のようにメッセージの末尾にコロンを付けて、ランタイム情報を追加できます。

<error_message>:<extra_info>

たとえば、closed statementエラーは次のように表示されることがあります。

Closed Statement:next

これは(結果セット・オブジェクトの)nextメソッドのコール中に例外がスローされたことを示します。

場合によっては、スタック・トレースになんらかの情報が見つかることがあります。

一般JDBCメッセージ

この項では、まずORA番号順、次に五十音順にソートした一般JDBCエラー・メッセージのリストを示しています。

- ORA番号でソートしたJDBCメッセージ

- 五十音順にソートしたJDBCメッセージ

注意:
エラー・メッセージORA-17033およびORA-17034では、SQL92という用語が使用されています。JDBCエスケープ構文は、以前はSQL92構文またはSQL92エスケープ構文と呼ばれていました。

ORA番号でソートしたJDBCメッセージ

次の表では、ORA番号順にソートしたJDBCエラー・メッセージを示しています。

表D-1 ORA番号でソートしたJDBCメッセージ

ORA番号

メッセージ

ORA-17001

内部エラー

ORA-17002

I/O例外です。

ORA-17003

列索引が無効です。

ORA-17004

列の型が無効です。

ORA-17005

サポートされない列の型です。

ORA-17006

列名が無効です。

ORA-17007

動的列が無効です。

ORA-17008

クローズされた接続です。

ORA-17009

クローズされた文です。

ORA-17010

クローズされた結果セットです。

ORA-17011

空の結果セットです。

ORA-17012

パラメータの型が競合します。

ORA-17014

ResultSet.nextはコールされませんでした。

ORA-17015

文は取り消されました。

ORA-17016

文は時間切れになりました。

ORA-17017

カーソルはすでに初期化済です。

ORA-17018

無効なカーソルです。

ORA-17019

1つの問合せのみ記述できます。

ORA-17020

行のプリフェッチが無効です。

ORA-17021

定義がありません。

ORA-17022

索引に定義がありません。

ORA-17023

サポートされない機能です。

ORA-17024

読み込むデータがありません。

ORA-17025

defines.isNull()でエラーが発生しました。

ORA-17026

数値のオーバーフローです。

ORA-17027

ストリームはすでにクローズ済です。

ORA-17028

現行の結果セットがクローズされるまで、新規結果セットを実行できません。

ORA-17029

setReadOnly: 読取り専用の接続はサポートされません。

ORA-17030

READ_COMMITTEDおよびSERIALIZABLEのみが有効なトランザクション・レベルです。

ORA-17031

setAutoClose: 自動クローズ・モードが「オン」の場合のみサポートされます。

ORA-17032

行のプリフェッチをゼロに設定できません。

ORA-17033

不完全なSQL92文字列です - 位置

ORA-17034

サポートされないSQL92トークンです - 位置

ORA-17035

サポートされないキャラクタ・セットです。

ORA-17036

OracleNumberで例外が発生しました。

ORA-17037

UTF8とUCS2との間の変換に失敗しました。

ORA-17038

バイト配列の長さが不十分です。

ORA-17039

文字配列の長さが不十分です。

ORA-17040

接続URLにサブ・プロトコルの指定が必要です。

ORA-17041

INまたはOUTパラメータがありません - 索引

ORA-17042

バッチの値が無効です。

ORA-17043

ストリームの最大サイズが無効です。

ORA-17044

内部エラー: データ配列を割当てできません。

ORA-17045

内部エラー: バッチの値範囲を超えてバインド変数にアクセスしようとしました。

ORA-17046

内部エラー: データ・アクセスに対する索引が無効です。

ORA-17047

型記述子の解析でエラーが発生しました。

ORA-17048

型が定義されていません。

ORA-17049

JAVAとSQLのオブジェクト型が適合しません。

ORA-17050

ベクトルにそのような要素はありません。

ORA-17051

このAPIは、UDT以外の型に使用できません。

ORA-17052

この参照は有効ではありません。

ORA-17053

サイズが無効です。

ORA-17054

LOB ロケータが無効です。

ORA-17055

無効なキャラクタが見つかりました -

ORA-17056

サポートされないキャラクタ・セットです(orai18n.jarをクラスパスに追加してください)

ORA-17057

クローズされたLOBです。

ORA-17058

内部エラー: NLS変換率が無効です。

ORA-17059

内部表現の変換に失敗しました。

ORA-17060

記述子の構成に失敗しました。

ORA-17061

記述子がありません。

ORA-17062

参照カーソルが無効です。

ORA-17063

トランザクション中ではありません。

ORA-17064

構文が無効、またはデータベース名がNULLです。

ORA-17065

変換クラスがNULLです。

ORA-17066

アクセス・レイヤーには固有の実装が必要です。

ORA-17067

無効なOracle URLが指定されました。

ORA-17068

コールに無効な引数があります。

ORA-17069

明示的なXAコールを使用してください。

ORA-17070

データ・サイズがこの型の最大サイズを超えています。

ORA-17071

最大VARRAY制限を超えました。

ORA-17072

列に対して挿入値が大きすぎます。

ORA-17074

名前パターンが無効です。

ORA-17075

転送専用の結果セットに対する操作が無効です。

ORA-17076

読取り専用の結果セットに対する操作が無効です。

ORA-17077

REF値の設定に失敗しました。

ORA-17078

接続はすでにオープンしているため、操作できません。

ORA-17079

既存のユーザー資格証明と一致しません。

ORA-17080

無効なバッチ・コマンドです。

ORA-17081

バッチ処理でエラーが発生しました。

ORA-17082

現行の行がありません。

ORA-17083

挿入行ではありません。

ORA-17084

挿入行でコールされました。

ORA-17085

値の競合が発生しました。

ORA-17086

挿入行の列値が未定義です。

ORA-17087

パフォーマンス・ヒントが無視されました: setFetchDirection()

ORA-17088

リクエストした結果セットの型と同時実行レベルの構文はサポートされていません。

ORA-17089

内部エラー

ORA-17090

操作できません。

ORA-17091

リクエストした型および/または同時実行レベルで結果セットを作成できません。

ORA-17092

コール処理の終了時にJDBC文を作成または実行できません。

ORA-17093

OCI操作でOCI_SUCCESS_WITH_INFOが戻りました。

ORA-17094

オブジェクト・タイプのバージョンが適合しません。

ORA-17095

文のキャッシュ・サイズが設定されていません。

ORA-17096

文のキャッシュはこの論理接続に対して使用可能にできません。

ORA-17097

PL/SQLの索引表の要素タイプが無効です。

ORA-17098

空のLOB操作は無効です。

ORA-17099

PL/SQLの索引表の配列の長さが無効です。

ORA-17100

データベースのJavaオブジェクトが無効です。

ORA-17101

OCI接続プール・オブジェクトに無効なプロパティがあります。

ORA-17102

Bfileは読取り専用です

ORA-17103

getConnection経由で戻る接続タイプは無効です。かわりに、getJavaSqlConnectionを使用してください

ORA-17104

実行するSQL文は空またはNULLにできません

ORA-17105

接続セッションのタイムゾーンが設定されていません

ORA-17106

指定されたJDBC-OCIドライバの接続プール構成が無効です

ORA-17107

無効なプロキシ・タイプが指定されました

ORA-17108

defineColumnTypeに最大長が指定されていません

ORA-17109

標準のJava文字エンコーディングが見つかりません

ORA-17110

実行が警告で完了しました

ORA-17111

無効な接続キャッシュTTLのタイムアウトが指定されました。

ORA-17112

指定されたスレッド間隔が無効です

ORA-17113

スレッド間隔値が、キャッシュのタイムアウト値より大きいです

ORA-17114

グローバル・トランザクションでローカル・トランザクション・コミットを使用できませんでした。

ORA-17115

グローバル・トランザクションでローカル・トランザクション・ロールバックを使用できませんでした。

ORA-17116

アクティブなグローバル・トランザクションで自動コミットをオンにできませんでした

ORA-17117

アクティブなグローバル・トランザクションでセーブポイントを設定できませんでした

ORA-17118

名前付きセーブポイントのIDを取得できませんでした。

ORA-17119

名前付きでないセーブポイントの名前を取得できませんでした。

ORA-17120

自動コミットがオンの状態でセーブポイントを設定できませんでした。

ORA-17121

自動コミットがオンの状態でセーブポイントにロールバックできませんでした。

ORA-17122

グローバル・トランザクションでローカル・トランザクション・セーブポイントにロールバックできません

ORA-17123

無効な文キャッシュ・サイズが指定されました。

ORA-17124

無効な接続キャッシュのInactivityタイムアウトが指定されました

ORA-17125

明示的なキャッシュにより不適切な文の種類が戻されました。

ORA-17126

指定待機タイムアウトを経過しました

ORA-17127

指定された固定待機タイムアウトが無効です

ORA-17128

SQL文字列が問合せではありません

ORA-17129

SQL文字列がDML文ではありません

ORA-17132

無効な変換がリクエストされました

ORA-17133

未使用

ORA-17134

SQLの名前指定パラメータの長さが32文字を超えています

ORA-17135

setXXXStreamで使用されたパラメータ名が、SQLで複数回使用されています

ORA-17136

DATALINK URLの形式に誤りがあります。かわりにgetString()を試行してください

ORA-17137

接続キャッシュが使用可能ではないか、またはキャッシュが使用可能な有効なDataSourceではありません

ORA-17138

接続キャッシュ名が無効です。有効な文字列で一意である必要があります

ORA-17139

接続キャッシュ・プロパティが無効です

ORA-17140

このキャッシュ名の接続キャッシュはすでに存在します

ORA-17141

このキャッシュ名の接続キャッシュは存在しません

ORA-17142

このキャッシュ名の接続キャッシュは無効です

ORA-17143

無効または失効している接続が接続キャッシュ内に見つかりました

ORA-17144

文の処理が実行されません

ORA-17145

無効なONSイベントを受信しました

ORA-17146

無効なONSイベントのバージョンを受信しました

ORA-17147

SQLに存在しないパラメータ名の設定を試行しました

ORA-17148

Thinでのみ実装されるメソッド

ORA-17149

これはすでにプロキシ・セッションです

ORA-17150

プロキシ・セッションの不正な引数です

ORA-17151

CLOBは大きすぎてJava文字列に格納できません

ORA-17152

このメソッドは論理接続でのみ実装されます

ORA-17153

このメソッドは物理接続でのみ実装されます

ORA-17154

OracleキャラクタをUnicodeにマップできません

ORA-17155

UnicodeをOracleキャラクタにマップできません

ORA-17156

エンドツーエンドのメトリック値の配列サイズが無効です

ORA-17157

setStringでは、32766文字未満の文字列のみ処理できます

ORA-17158

この関数では継続時間が無効です

ORA-17159

エンドツーエンドのトレースのメトリック値が長すぎます

ORA-17160

実行コンテキストIDの順序番号が範囲外です

ORA-17161

使用されたトランザクション・モードが無効です

ORA-17162

サポートされていないholdability値です

ORA-17163

接続キャッシュが使用可能な場合は、getXAConnection()を使用できません

ORA-17164

キャッシュが有効な物理接続からはgetXAResource()をコールできません

ORA-17165

この接続のサーバーにはDBMS_JDBCパッケージが事前に設定されていません

ORA-17166

PLSQL文でfetchを実行できません

ORA-17167

PKIクラスが見つかりません。'connect /'機能を使用するには、oraclepki.jarをCLASSPATHに指定する必要があります

ORA-17168

Secret Storeで問題が発生しました。ウォレット・ロケーションを調べ、オープン・ウォレット(cwallet.sso)の有無を確認してください。また、mkstoreユーティリティを使用して、このウォレットに適切な資格証明が含まれていることを確認してください

ORA-17169

ストリームをScrollableResultSetまたはUpdatableResultSetにバインドできません

ORA-17170

ネームスペースは空にできません

ORA-17171

属性の長さは30文字を超えてはいけません

ORA-17172

属性の値は400文字を超えてはいけません

ORA-17173

すべてのリターン・パラメータが登録されていません

ORA-17174

サポートされているネームスペースはCLIENTCONTEXTだけです

ORA-17175

リモートONS構成中のエラー

ORA-17259

SQLXMLは、クラスパスにXMLサポートjarファイルを見つけられません

ORA-17260

空のSQLXMLを読み取ろうとしています

ORA-17261

読取り不可能なSQLXMLを読み取ろうとしています

ORA-17262

書込み不可能なSQLXMLに書き込もうとしています

ORA-17263

SQLXMLは、そのタイプの結果を作成できません

ORA_17264

SQLXMLは、そのタイプのソースを作成できません

五十音順にソートしたJDBCメッセージ

次の表では、五十音順にソートしたJDBCエラー・メッセージを示しています。

表D-2 五十音順にソートしたJDBCメッセージ

ORA番号

メッセージ

ORA-17066

アクセス・レイヤーには固有の実装が必要です。

ORA-17261

読取り不可能なSQLXMLを読み取ろうとしています

ORA-17260

空のSQLXMLを読み取ろうとしています

ORA-17147

SQLに存在しないパラメータ名の設定を試行しました

ORA-17262

書込み不可能なSQLXMLに書き込もうとしています

ORA-17102

Bfileは読取り専用です

ORA-17038

バイト配列の長さが不十分です。

ORA-17084

挿入行でコールされました。

ORA-17164

キャッシュが有効な物理接続からはgetXAResource()をコールできません

ORA-17028

現行の結果セットがクローズされるまで、新規結果セットを実行できません。

ORA-17163

接続キャッシュが使用可能な場合は、getXAConnection()を使用できません

ORA-17019

1つの問合せのみ記述できます。

ORA-17169

ストリームをScrollableResultSetまたはUpdatableResultSetにバインドできません

ORA-17078

接続はすでにオープンしているため、操作できません。

ORA-17154

OracleキャラクタをUnicodeにマップできません

ORA-17155

UnicodeをOracleキャラクタにマップできません

ORA-17166

PLSQL文でfetchを実行できません

ORA-17032

行のプリフェッチをゼロに設定できません。

ORA-17039

文字配列の長さが不十分です。

ORA-17035

サポートされないキャラクタ・セットです。

ORA-17151

CLOBは大きすぎてJava文字列に格納できません

ORA-17008

クローズされた接続です。

ORA-17057

クローズされたLOBです。

ORA-17010

クローズされた結果セットです。

ORA-17009

クローズされた文です。

ORA-17140

このキャッシュ名の接続キャッシュはすでに存在します

ORA-17141

このキャッシュ名の接続キャッシュは存在しません

ORA-17142

このキャッシュ名の接続キャッシュは無効です

ORA-17137

接続キャッシュが使用可能ではないか、またはキャッシュが使用可能な有効なDataSourceではありません

ORA-17105

接続セッションのタイムゾーンが設定されていません

ORA-17065

変換クラスがNULLです。

ORA-17118

名前付きセーブポイントのIDを取得できませんでした。

ORA-17119

名前付きでないセーブポイントの名前を取得できませんでした。

ORA-17122

グローバル・トランザクションでローカル・トランザクション・セーブポイントにロールバックできません

ORA-17121

自動コミットがオンの状態でセーブポイントにロールバックできませんでした。

ORA-17120

自動コミットがオンの状態でセーブポイントを設定できませんでした。

ORA-17117

アクティブなグローバル・トランザクションでセーブポイントを設定できませんでした

ORA-17116

アクティブなグローバル・トランザクションで自動コミットをオンにできませんでした

ORA-17114

グローバル・トランザクションでローカル・トランザクション・コミットを使用できませんでした。

ORA-17115

グローバル・トランザクションでローカル・トランザクション・ロールバックを使用できませんでした。

ORA-17017

カーソルはすでに初期化済です。

ORA-17070

データ・サイズがこの型の最大サイズを超えています。

ORA-17165

この接続のサーバーにはDBMS_JDBCパッケージが事前に設定されていません

ORA-17158

この関数では継続時間が無効です

ORA-17168

Secret Storeで問題が発生しました。ウォレット・ロケーションを調べ、オープン・ウォレット(cwallet.sso)の有無を確認してください。また、mkstoreユーティリティを使用して、このウォレットに適切な資格証明が含まれていることを確認してください

ORA-17175

リモートONS構成中のエラー

ORA-17025

defines.isNull()でエラーが発生しました。

ORA-17047

型記述子の解析でエラーが発生しました。

ORA-17081

バッチ処理でエラーが発生しました。

ORA-17071

最大VARRAY制限を超えました。

ORA-17036

OracleNumberで例外が発生しました。

ORA-17110

実行が警告で完了しました

ORA-17160

実行コンテキストIDの順序番号が範囲外です

ORA-17011

空の結果セットです。

ORA-17060

記述子の構成に失敗しました。

ORA-17037

UTF8とUCS2との間の変換に失敗しました。

ORA-17059

内部表現の変換に失敗しました。

ORA-17077

REF値の設定に失敗しました。

ORA-17126

指定待機タイムアウトを経過しました

ORA-17087

パフォーマンス・ヒントが無視されました: setFetchDirection()

ORA-17125

明示的なキャッシュにより不適切な文の種類が戻されました。

ORA-17049

JAVAとSQLのオブジェクト型が適合しません。

ORA-17072

列に対して挿入値が大きすぎます。

ORA-17001

内部エラー

ORA-17089

内部エラー

ORA-17045

内部エラー: バッチの値範囲を超えてバインド変数にアクセスしようとしました。

ORA-17044

内部エラー: データ配列を割当てできません。

ORA-17046

内部エラー: データ・アクセスに対する索引が無効です。

ORA-17058

内部エラー: NLS変換率が無効です。

ORA-17068

コールに無効な引数があります。

ORA-17156

エンドツーエンドのメトリック値の配列サイズが無効です

ORA-17080

無効なバッチ・コマンドです。

ORA-17042

バッチの値が無効です。

ORA-17055

無効なキャラクタが見つかりました -

ORA-17003

列索引が無効です。

ORA-17006

列名が無効です。

ORA-17004

列の型が無効です。

ORA-17124

無効な接続キャッシュのInactivityタイムアウトが指定されました

ORA-17138

接続キャッシュ名が無効です。有効な文字列で一意である必要があります

ORA-17139

接続キャッシュ・プロパティが無効です

ORA-17111

無効な接続キャッシュTTLのタイムアウトが指定されました。

ORA-17103

getConnection経由で戻る接続タイプは無効です。かわりに、getJavaSqlConnectionを使用してください

ORA-17132

無効な変換がリクエストされました

ORA-17018

無効なカーソルです。

ORA-17100

データベースのJavaオブジェクトが無効です。

ORA-17007

動的列が無効です。

ORA-17098

空のLOB操作は無効です。

ORA-17127

指定された固定待機タイムアウトが無効です

ORA-17106

指定されたJDBC-OCIドライバの接続プール構成が無効です

ORA-17074

名前パターンが無効です。

ORA-17145

無効なONSイベントを受信しました

ORA-17146

無効なONSイベントのバージョンを受信しました

ORA-17075

転送専用の結果セットに対する操作が無効です。

ORA-17076

読取り専用の結果セットに対する操作が無効です。

ORA-17143

無効または失効している接続が接続キャッシュ内に見つかりました

ORA-17067

無効なOracle URLが指定されました。

ORA-17099

PL/SQLの索引表の配列の長さが無効です。

ORA-17097

PL/SQLの索引表の要素タイプが無効です。

ORA-17101

OCI接続プール・オブジェクトに無効なプロパティがあります。

ORA-17107

無効なプロキシ・タイプが指定されました

ORA-17020

行のプリフェッチが無効です。

ORA-17123

無効な文キャッシュ・サイズが指定されました。

ORA-17043

ストリームの最大サイズが無効です。

ORA-17064

構文が無効、またはデータベース名がNULLです。

ORA-17112

指定されたスレッド間隔が無効です

ORA-17161

使用されたトランザクション・モードが無効です

ORA-17002

I/O例外です。

ORA-17092

コール処理の終了時にJDBC文を作成または実行できません。

ORA-17134

SQLの名前指定パラメータの長さが32文字を超えています

ORA-17136

DATALINK URLの形式に誤りがあります。かわりにgetString()を試行してください

ORA-17033

不完全なSQL92文字列です - 位置

ORA-17148

Thinでのみ実装されるメソッド

ORA-17159

エンドツーエンドのトレースのメトリック値が長すぎます

ORA-17021

定義がありません。

ORA-17022

索引に定義がありません。

ORA-17061

記述子がありません。

ORA-17041

INまたはOUTパラメータがありません - 索引

ORA-17082

現行の行がありません。

ORA-17024

読み込むデータがありません。

ORA-17108

defineColumnTypeに最大長が指定されていません

ORA-17050

ベクトルにそのような要素はありません。

ORA-17056

サポートされないキャラクタ・セットです(orai18n.jarをクラスパスに追加してください)

ORA-17034

サポートされないSQL92トークンです - 位置

ORA-17173

すべてのリターン・パラメータが登録されていません

ORA-17063

トランザクション中ではありません。

ORA-17083

挿入行ではありません。

ORA-17026

数値のオーバーフローです。

ORA-17094

オブジェクト・タイプのバージョンが適合しません。

ORA-17093

OCI操作でOCI_SUCCESS_WITH_INFOが戻りました。

ORA-17090

操作できません。

ORA-17135

setXXXStreamで使用されたパラメータ名が、SQLで複数回使用されています

ORA-17012

パラメータの型が競合します。

ORA-17167

PKIクラスが見つかりません。'connect /'機能を使用するには、oraclepki.jarをCLASSPATHに指定する必要があります

ORA-17030

READ_COMMITTEDおよびSERIALIZABLEのみが有効なトランザクション・レベルです。

ORA-17062

参照カーソルが無効です。

ORA-17014

ResultSet.nextはコールされませんでした。

ORA-17031

setAutoClose: 自動クローズ・モードが「オン」の場合のみサポートされます。

ORA-17029

setReadOnly: 読取り専用の接続はサポートされません。

ORA-17157

setStringでは、32766文字未満の文字列のみ処理できます

ORA-17104

実行するSQL文は空またはNULLにできません

ORA-17129

SQL文字列がDML文ではありません

ORA-17128

SQL文字列が問合せではありません

ORA-17263

SQLXMLは、そのタイプの結果を作成できません

ORA_17264

SQLXMLは、そのタイプのソースを作成できません

ORA-17259

SQLXMLは、クラスパスにXMLサポートjarファイルを見つけられません

ORA-17109

標準のJava文字エンコーディングが見つかりません

ORA-17095

文のキャッシュ・サイズが設定されていません。

ORA-17096

文のキャッシュはこの論理接続に対して使用可能にできません。

ORA-17144

文の処理が実行されません

ORA-17016

文は時間切れになりました。

ORA-17015

文は取り消されました。

ORA-17027

ストリームはすでにクローズ済です。

ORA-17040

接続URLにサブ・プロトコルの指定が必要です。

ORA-17172

属性の値は400文字を超えてはいけません

ORA-17171

属性の長さは30文字を超えてはいけません

ORA-17054

LOB ロケータが無効です。

ORA-17170

ネームスペースは空にできません

ORA-17174

サポートされているネームスペースはCLIENTCONTEXTだけです

ORA-17053

サイズが無効です。

ORA-17051

このAPIは、UDT以外の型に使用できません。

ORA-17149

これはすでにプロキシ・セッションです

ORA-17152

このメソッドは論理接続でのみ実装されます

ORA-17153

このメソッドは物理接続でのみ実装されます

ORA-17052

この参照は有効ではありません。

ORA-17113

スレッド間隔値が、キャッシュのタイムアウト値より大きいです

ORA-17091

リクエストした型および/または同時実行レベルで結果セットを作成できません。

ORA-17086

挿入行の列値が未定義です。

ORA-17048

型が定義されていません。

ORA-17005

サポートされない列の型です。

ORA-17023

サポートされない機能です。

ORA-17162

サポートされていないholdability値です

ORA-17088

リクエストした結果セットの型と同時実行レベルの構文はサポートされていません。

ORA-17133

未使用

ORA-17069

明示的なXAコールを使用してください。

ORA-17079

既存のユーザー資格証明と一致しません。

ORA-17085

値の競合が発生しました。

ORA-17150

プロキシ・セッションの不正な引数です

ネイティブXAメッセージ

次の項では、ネイティブXA機能に固有のJDBCエラー・メッセージを示します。

- ORA番号でソートしたネイティブXAメッセージ

- 五十音順にソートしたネイティブXAメッセージ

ORA番号でソートしたネイティブXAメッセージ

次の表では、ORA番号順にソートしたネイティブXAメッセージを示しています。

表D-3 ORA番号でソートしたネイティブXAメッセージ

ORA番号

メッセージ

ORA-17200

XA open文字列をJavaからCへ正しく変換できません

ORA-17201

XA close文字列をJavaからCへ正しく変換できません

ORA-17202

RM名をJavaからCへ正しく変換できません

ORA-17203

ポインタ・タイプをjlongにキャストできません

ORA-17204

入力配列が短かすぎてOCIハンドルを保持できません

ORA-17205

xaoSvcCtxを使用してC-XAからOCISvcCtxハンドルを取得するのに失敗しました

ORA-17206

xaoEnvを使用してC-XAからOCIEnvを取得するのに失敗しました

ORA-17207

tnsEntryプロパティがDataSourceに設定されていません

ORA-17213

xa_openでC-XAからXAER_RMERRが戻されました

ORA-17215

xa_openでC-XAからXAER_INVALが戻されました

ORA-17216

xa_openでC-XAからXAER_PROTOが戻されました

ORA-17233

xa_closeでC-XAからXAER_RMERRが戻されました

ORA-17235

xa_closeでC-XAからXAER_INVALが戻されました

ORA-17236

xa_closeでC-XAからXAER_PROTOが戻されました

五十音順にソートしたネイティブXAメッセージ

次の表では、五十音順にソートしたネイティブXAメッセージを示しています。

表D-4 五十音順にソートしたネイティブXAメッセージ

ORA番号

メッセージ

ORA-17203

ポインタ・タイプをjlongにキャストできません

ORA-17235

xa_closeでC-XAからXAER_INVALが戻されました

ORA-17215

xa_openでC-XAからXAER_INVALが戻されました

ORA-17236

xa_closeでC-XAからXAER_PROTOが戻されました

ORA-17216

xa_openでC-XAからXAER_PROTOが戻されました

ORA-17233

xa_closeでC-XAからXAER_RMERRが戻されました

ORA-17213

xa_openでC-XAからXAER_RMERRが戻されました

ORA-17206

xaoEnvを使用してC-XAからOCIEnvを取得するのに失敗しました

ORA-17205

xaoSvcCtxを使用してC-XAからOCISvcCtxハンドルを取得するのに失敗しました

ORA-17204

入力配列が短かすぎてOCIハンドルを保持できません

ORA-17207

tnsEntryプロパティがDataSourceに設定されていません

ORA-17202

RM名をJavaからCへ正しく変換できません

ORA-17201

XA close文字列をJavaからCへ正しく変換できません

ORA-17200

XA open文字列をJavaからCへ正しく変換できません

TTCメッセージ

この項では、まずORA番号順、次に五十音順にソートしたTTCエラー・メッセージを示します。

- ORA番号でソートしたTTCメッセージ

- 五十音順にソートしたTTCメッセージ

ORA番号でソートしたTTCメッセージ

次の表では、ORA番号順にソートしたTTCメッセージを示しています。

表D-5 ORA番号でソートしたTTCメッセージ

ORA番号

メッセージ

ORA-17401

プロトコル違反です。

ORA-17402

RPAメッセージは1つのはずです。

ORA-17403

RXHメッセージは1つのはずです。

ORA-17404

予定より多いRXDを受け取りました。

ORA-17405

UACの長さはゼロではありません。

ORA-17406

最大バッファ長を超えています。

ORA-17407

型表現が無効です(setRep)。

ORA-17408

型表現が無効です(getRep)。

ORA-17409

バッファ長が無効です。

ORA-17410

ソケットから読み込むデータはこれ以上ありません。

ORA-17411

データ型の表現が適合しません。

ORA-17412

型の長さが最大を超えています。

ORA-17413

キー・サイズが大きすぎます。

ORA-17414

列名を保存するにはバッファ・サイズが不十分です。

ORA-17415

この型は未処理です。

ORA-17416

FATAL

ORA-17417

NLSの問題で、列名のデコードに失敗しました。

ORA-17418

内部構造体のフィールド長エラーです。

ORA-17419

無効な列の数が戻りました。

ORA-17420

Oracleバージョンが定義されていません。

ORA-17421

型または接続が定義されていません。

ORA-17422

ファクトリに無効なクラスがあります。

ORA-17423

IOVの定義なしでPLSQLブロックを使用しています。

ORA-17424

異なる配列操作を試みています。

ORA-17425

PLSQLブロックでストリームを戻しています。

ORA-17426

INバインド、OUTバインドともにNULLです。

ORA-17427

初期化されていないOACを使用しています。

ORA-17428

接続後にログオンのコールが必要です。

ORA-17429

少なくともサーバーに接続している必要があります。

ORA-17430

サーバーへのログオンが必要です。

ORA-17431

解析するSQL文がNULLです。

ORA-17432

all7でオプションが無効です。

ORA-17433

コールの引数が無効です。

ORA-17434

ストリーム・モードではありません。

ORA-17435

IOVでin_out_bindsの数が無効です。

ORA-17436

アウトバインドの数が無効です。

ORA-17437

PLSQLブロックのIN/OUT引数にエラーがあります。

ORA-17438

内部 - 予期しない値です。

ORA-17439

SQLの型が無効です。

ORA-17440

DBItem/DBTypeがNULLです。

ORA-17441

このOracleバージョンはサポートされません。7.2.3以上はサポートされます。

ORA-17442

Refcursor値が無効です。

ORA-17443

NULLのユーザーまたはパスワードは、THINドライバでサポートされません。

ORA-17444

サーバーから受け取ったTTCプロトコル・バージョンはサポートされません。

ORA-17445

LOBは、同じトランザクションですでにオープンされています

ORA-17446

LOBは、同じトランザクションですでにクローズされています

ORA-17447

OALL8矛盾した状態にあります

五十音順にソートしたTTCメッセージ

次の表では、五十音順にソートしたTTCメッセージを示しています。

表D-6 五十音順にソートしたTTCメッセージ

ORA番号

メッセージ

ORA-17424

異なる配列操作を試みています。

ORA-17412

型の長さが最大を超えています。

ORA-17426

INバインド、OUTバインドともにNULLです。

ORA-17411

データ型の表現が適合しません。

ORA-17440

DBItem/DBTypeがNULLです。

ORA-17437

PLSQLブロックのIN/OUT引数にエラーがあります。

ORA-17413

キー・サイズが大きすぎます。

ORA-17406

最大バッファ長を超えています。

ORA-17416

FATAL

ORA-17414

列名を保存するにはバッファ・サイズが不十分です。

ORA-17438

内部 - 予期しない値です。

ORA-17418

内部構造体のフィールド長エラーです。

ORA-17433

コールの引数が無効です。

ORA-17409

バッファ長が無効です。

ORA-17422

ファクトリに無効なクラスがあります。

ORA-17419

無効な列の数が戻りました。

ORA-17435

IOVでin_out_bindsの数が無効です。

ORA-17436

アウトバインドの数が無効です。

ORA-17432

all7でオプションが無効です。

ORA-17439

SQLの型が無効です。

ORA-17408

型表現が無効です(getRep)。

ORA-17407

型表現が無効です(setRep)。

ORA-17446

LOBは、同じトランザクションですでにクローズされています

ORA-17445

LOBは、同じトランザクションですでにオープンされています

ORA-17428

接続後にログオンのコールが必要です。

ORA-17429

少なくともサーバーに接続している必要があります。

ORA-17430

サーバーへのログオンが必要です。

ORA-17417

NLSの問題で、列名のデコードに失敗しました。

ORA-17410

ソケットから読み込むデータはこれ以上ありません。

ORA-17434

ストリーム・モードではありません。

ORA-17443

NULLのユーザーまたはパスワードは、THINドライバでサポートされません。

ORA-17447

OALL8矛盾した状態にあります

ORA-17402

RPAメッセージは1つのはずです。

ORA-17403

RXHメッセージは1つのはずです。

ORA-17420

Oracleバージョンが定義されていません。

ORA-17441

このOracleバージョンはサポートされません。7.2.3以上はサポートされます。

ORA-17401

プロトコル違反です。

ORA-17404

予定より多いRXDを受け取りました。

ORA-17442

Refcursor値が無効です。

ORA-17425

PLSQLブロックでストリームを戻しています。

ORA-17431

解析するSQL文がNULLです。

ORA-17415

この型は未処理です。

ORA-17444

サーバーから受け取ったTTCプロトコル・バージョンはサポートされません。

ORA-17421

型または接続が定義されていません。

ORA-17405

UACの長さはゼロではありません。

ORA-17423

IOVの定義なしでPLSQLブロックを使用しています。

ORA-17427

初期化されていないOACを使用しています。

E トラブルシューティング

この付録では、Java Database Connectivity(JDBC)アプリケーションまたはアプレットのトラブルシューティングについて説明します。内容は次のとおりです。

- 一般的な問題

- 基本的なデバッグ処理

一般的な問題

この項では、Oracle JDBCドライバの使用中に発生する可能性のある、一般的な問題について説明します。たとえば、次の問題があります。

- OUTまたはIN/OUT変数として定義されたCHAR列に対するメモリー消費

- メモリー・リークおよびカーソルの不足

- PL/SQLストアド・プロシージャのブール型パラメータ

- 1プロセスで可能なOCI接続のオープン数について

- Statement.cancelの使用

- ファイアウォールとJDBCの使用方法

- 多数回にわたるサーバーからの突然の切断

OUTまたはIN/OUT変数として定義されたCHAR列に対するメモリー消費

PL/SQLでは、CHARまたはVARCHAR2列がOUTまたはIN/OUT変数として定義される場合、ドライバは32512文字のCHAR配列を割り当てます。このため、メモリー消費に関する問題が生じます。JDBC Thinドライバは、VARCHAR2出力型を使用する場合、メモリーを割り当てません。ただし、JDBC OCIドライバは、CHARとVARCHAR2の両方の型に対してメモリーを割り当てます。このため、OCIドライバのCPU負荷はThinドライバより高くなります。

以前のリリースでは、この問題はStatement.setMaxFieldSizeメソッドをコールすることで解決できました。これよりもよい解決方法は、OracleCallableStatement.registerOutParameterを使用することです。すべてのCHARまたはVARCHAR2列で、必ずregisterOutParameter(int paramIndex, int sqlType, int scale, int maxLength)をコールすることをお薦めします。このメソッドは、oracle.jdbc.driver.OracleCallableStatementに定義されています。4つ目の引数maxLengthを使用して、メモリー消費を制限します。このパラメータは、この列の格納に必要な文字数をドライバに指示します。文字配列に列データを保持できない場合、列は切り捨てられます。3つ目の引数scaleは、ドライバでは無視されます。

メモリー・リークおよびカーソルの不足

カーソルまたはメモリーが不足しているというメッセージを受け取った場合は、すべてのStatementおよびResultSetオブジェクトを明示的にクローズしてください。Oracle JDBCドライバには、ファイナライザ・メソッドがありません。クリーン・アップ・ルーチンは、ResultSetおよびStatementクラスのcloseメソッドで実行されます。結果セットおよび文オブジェクトを明示的にクローズしておかないと、重大なメモリー・リークが発生します。また、データベースのカーソルが不足します。文をクローズすると、データベース内の対応するカーソルが解放されます。

同様に、サーバー側でのリークおよびカーソル不足を避けるには、Connectionオブジェクトも明示的にクローズしておく必要があります。接続をクローズすると、その接続に関連付けられたオープン中の文オブジェクトが、JDBCドライバによってクローズされ、サーバー側のカーソルが解放されます。

PL/SQLストアド・プロシージャのブール型パラメータ

JDBCドライバでは、PL/SQLストアド・プロシージャにBOOLEANパラメータを渡せません。PL/SQLプロシージャにBOOLEAN値が含まれている場合、そのPL/SQLプロシージャを、引数をINTとして受け取る2番目のPL/SQLプロシージャでラップし、最初のストアド・プロシージャに渡します。2番目のプロシージャがコールされると、サーバーによってINTからBOOLEANに変換されます。

ストアド・プロシージャの例を示します。BOOLPROCは、BOOLEANパラメータを渡そうとします。2番目のプロシージャBOOLWRAPは、BOOLEAN値とINT値の置換えを実行します。

CREATE OR REPLACE PROCEDURE boolproc(x boolean)
AS
BEGIN
[...]
END;

CREATE OR REPLACE PROCEDURE boolwrap(x int)
AS
BEGIN
IF (x=1) THEN
boolproc(TRUE);
ELSE
boolproc(FALSE);
END IF;
END;

// Create the database connection from a DataSource
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@<...hoststring...>");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
CallableStatement cs = conn.prepareCall ("begin boolwrap(?); end;");
cs.setInt(1, 1);
cs.execute ();

1プロセスで可能なOCI接続のオープン数について

必ずしも1プロセスで約17以上のJDBC-OCI接続をオープンできないことがあります。サーバー上のプロセス数が初期化ファイルに指定されている制限を超えたためか、またはプロセスごとのファイル記述子の制限を超えた可能性があります。1つのJDBC-OCI接続で、複数のファイル記述子が使用される(3から4個のファイル記述子が使用されます)ことがあります。

サーバーで17以上のプロセスを使用可能にしている場合は、プロセスごとのファイル記述子の制限が原因である可能性があります。この制限数を増やすと、解決する可能性があります。

Statement.cancelの使用

JDBC標準メソッドStatement.cancelは、データベースにメッセージを送信することにより、SQL文の実行を正常に停止させます。データベースは、これに応答して実行を停止し、エラー・メッセージを返します。Statement.executeをコールしたJavaスレッドはサーバーで待機し、他のスレッドからのStatement.cancelコールにより呼び出された返答のエラー・メッセージを受信した場合にのみ実行を続けます。

このため、Statement.cancelは、ネットワークとデータベースが正しく機能していることに依存します。ネットワーク接続が切断するか、データベース・サーバーがダウンした場合、クライアントは取消しメッセージに対するエラー応答を受け取りません。サーバー・プロセスに障害が発生すると、多くの場合、JDBCはStatement.executeをコールしたスレッドを解放するIOExceptionを受け取ります。ただし、サーバーがダウンしてもJDBCがIOExceptionを受け取らない場合があります。Statement.executeを開始したスレッドは、Statement.cancelによって解放されません。

JDBCがIOExceptionを受け取らない場合は、Oracle Netがいずれはタイムアウトし、接続をクローズすることになります。これにより、IOExceptionが発生し、スレッドが解放されます。ただし、このプロセスにはかなりの時間がかかることがあります。このタイムアウトを制御する方法は、OracleDatasource.setConnectionProperties()のreadTimeoutプロパティの説明を参照してください。このタイムアウトは、Oracle Netの設定を使用してチューニングすることもできます。詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。

JDBC標準メソッドStatement.setQueryTimeoutは、Statement.cancelに依存します。指定されたタイムアウト間隔よりも実行時間が長くなった場合、モニター・スレッドがStatement.cancelをコールします。これは、前述と同じすべての制限を受けます。この結果、Statement.executeをコールしたスレッドがタイムアウトにより解放されない場合があります。

実行と取消しの間の時間の長さは、それほど正確ではありません。この間隔は、指定されたタイムアウト間隔より短くはなりませんが、数秒間長くなることがあります。アプリケーションに、高い優先順位で実行されているアクティブ・スレッドがある場合、この間隔は随意に長くなることがあります。モニター・スレッドは高い優先順位で実行されますが、他にも高い優先順位のスレッドがあり、それが実行し続けられる場合があります。モニター・スレッドが開始されるのは、ゼロ以外のタイムアウトで実行される文がある場合のみです。すべてのOracle JDBC文の実行を監視するモニター・スレッドは、1つのみあります。

Statement.cancelとStatement.setQueryTimeoutは、サーバー側内部ドライバでサポートされません。サーバー側内部ドライバは単一スレッドのサーバー・プロセスで動作します。Oracle JVMはこの単一スレッド・プロセス内にJavaスレッドを実装します。サーバー側内部ドライバがSQL文を実行している場合、JavaスレッドはStatement.cancelをコールできません。これは、Oracle JDBC監視スレッドにも適用されます。

ファイアウォールとJDBCの使用方法

アイドル接続に対するファイアウォール・タイムアウトによって、接続が切断される場合があります。このために、JDBCアプリケーションが接続の待機中に停止する可能性があります。ファイアウォール・タイムアウトによって接続が切断されないようにするには、次の処理を1つ以上実行します。

- 接続キャッシュまたは接続プーリングを使用している場合は、接続キャッシュのInactivityタイムアウト値を、常にファイアウォールのアイドル・タイムアウト値より短い値に設定します。

- 接続プロパティとしてoracle.net.READ_TIMEOUTを渡してソケット上で読込みタイムアウトを有効にします。タイムアウト値はミリ秒で指定します。

- JDBC OCIドライバとJDBC Thinドライバの両方について、ネット記述子を使用してデータベースに接続し、接続記述子のDESCRIPTION句にENABLE=BROKENパラメータを指定します。また、TCP_KEEPALIVE_INTERVALの下限値も設定します。

- サーバー側のsqlnet.oraファイルにSQLNET.EXPIRE_TIME=1を設定して、Oracle Net DCDを使用可能にします。

多数回にわたるサーバーからの突然の切断

ネットワークの信頼性が低い場合、サーバーの接続が突然切断されても、クライアントでは頻繁に発生する切断を検出するのが困難です。デフォルトでは、Linux上で稼働するクライアントは、突然の切断を検出するのに7200秒(2時間)かかります。この値は、tcp_keepalive_timeプロパティの値と同じです。アプリケーションが切断をより迅速に検出するようにするには、tcp_keepalive_time、tcp_keepalive_intervalおよびtcp_keepalive_probesプロパティの値をオペレーティング・システム・レベルでより小さい値に設定する必要があります。

注意:
tcp_keepalive_intervalプロパティに小さい値を設定すると、ネットワーク上にプローブ・パケットが頻繁に送出され、システム速度が低下する可能性があります。そのため、このプロパティの値は、システム要件に基づいて適切に設定してください。

また、接続記述子のDESCRIPTION句にENABLE=BROKENパラメータを指定する必要があります。たとえば、次のようになります。

jdbc:oracle:thin:@(DESCRIPTION=(ENABLE=BROKEN)(ADDRESS=(PROTOCOL=tcp)(PORT=1521)(HOST=myhost))(CONNECT_DATA=(SID=orcl)))

基本的なデバッグ処理

JDBCプログラムのデバッグ方法について説明します。

- ネットワーク・イベントをトラップするためのOracle Netトレース

- サード・パーティのデバッグ・ツール

デバッグに役立つスタック・トレースの出力など、SQL例外の処理については、「SQL例外の処理」を参照してください。

ネットワーク・イベントをトラップするためのOracle Netトレース

クライアントおよびサーバーのOracle-Netトレースが、Oracle Net経由で送信されるパケットをトラップできるようにできます。クライアント側トレースはJDBC OCIドライバについてのみ使用できます。JDBC Thinドライバについてはサポートされません。トレースとトレース・ファイルの読取りに関する詳細な情報は、Oracle Net Services管理者ガイドを参照してください。

トレース機能を使用すると、ネットワーク・イベントが実行されるたびにそのイベントについて記述される、一連の詳細な文が生成されます。操作をトレースすることにより、イベントの内部操作に関する詳細な情報を取り出すことができます。この情報は読込み可能ファイルに出力され、エラーの原因となったイベントを特定できます。トレース情報の収集は、SQLNET.ORAファイルにあるいくつかのOracle Netパラメータによって制御されます。SQLNET.ORAのパラメータを設定した後に、トレースを実行するために新しい接続を作成する必要があります。

トレース・レベルを高くすると、より詳細な情報がトレース・ファイルに取得されます。トレース・ファイルの理解が難しくなるため、トレースを有効にする場合はトレース・レベル4から開始します。トレース・ファイルの最初の部分は接続ハンドシェイク情報です。JDBCプログラムに関連するSQL文とエラー・メッセージの情報は、その先を参照してください。

注意:
トレース機能ではディスク領域が大量に使用されるため、システムのパフォーマンスが大幅に低下する可能性があります。トレースは、必要なときにのみ使用可能にしてください。

クライアント側でのトレース

クライアント・システムのSQLNET.ORAファイルに、次のパラメータを設定します。

TRACE_LEVEL_CLIENT

目的

トレースを一定の指定レベルでオン/オフにします。

デフォルト値

0またはOFF

有効な値

- 0またはOFF- トレースの出力なし

- 4またはUSER- ユーザー・トレース情報

- 10またはADMIN- 管理トレース情報

- 16またはSUPPORT- カスタマ・サポート・トレース情報

例:

TRACE_LEVEL_CLIENT=10

TRACE_DIRECTORY_CLIENT

目的

トレース・ファイルの書込み先ディレクトリを指定します。

デフォルト値

ORACLE_HOME/network/trace

例:

UNIX: TRACE_DIRECTORY_CLIENT=/oracle/traces

Windows: TRACE_DIRECTORY_CLIENT=C:\ORACLE\TRACES

TRACE_FILE_CLIENT

目的

クライアント・トレース・ファイルの名前を指定します。

デフォルト値

SQLNET.TRC

例:

TRACE_FILE_CLIENT=cli_Connection1.trc

注意:
TRACE_FILE_CLIENTファイルのために選択する名前は、TRACE_FILE_SERVERファイルのために選択する名前と異なっている必要があります。

TRACE_UNIQUE_CLIENT

目的

クライアント側の各トレースに一意の名前を付け、各トレース・ファイルが次に発生したクライアント・トレースによって上書きされないようにします。ファイル名の最後にPIDが付加されます。

デフォルト値

OFF

例:

TRACE_UNIQUE_CLIENT = ON

サーバー側のトレース

サーバー・システムのSQLNET.ORAファイルに次のパラメータを設定します。接続ごとに、一意のファイル名を持つ個別のファイルが生成されます。

TRACE_LEVEL_SERVER

目的

トレースを一定の指定レベルでオン/オフにします。

デフォルト値

0またはOFF

有効な値

- 0またはOFF- トレースの出力なし

- 4またはUSER- ユーザー・トレース情報

- 10またはADMIN- 管理トレース情報

- 16またはSUPPORT- カスタマ・サポート・トレース情報

例:

TRACE_LEVEL_SERVER=10

TRACE_DIRECTORY_SERVER

目的

トレース・ファイルの書込み先ディレクトリを指定します。

デフォルト値

ORACLE_HOME/network/trace

例:

TRACE_DIRECTORY_SERVER=/oracle/traces

TRACE_FILE_SERVER

目的

サーバー・トレース・ファイルの名前を指定します。

デフォルト値

SERVER.TRC

例:

TRACE_FILE_SERVER= svr_Connection1.trc

注意:
TRACE_FILE_SERVERファイルのために選択する名前は、TRACE_FILE_CLIENTファイルのために選択する名前と異なっている必要があります。

サード・パーティのデバッグ・ツール

Intersolv社のJDBCSpyおよびJDBCTestなどのツールを使用して、JDBC APIレベルで問題に対処できます。これらのツールは、ODBCSpyやODBCTestと類似しています。

索引

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  W  X

A

acceptChanges()メソッド, 18.2

PL/SQL索引付き表へのアクセス, 4.2.6

addBatch()メソッド, 23.1.3.2

ANYDATA, 4.5.4

ANYTYPE, 4.5.4

APPLET HTMLタグ, 5.3.5.1

アプレット

データベースへの接続, 5.3.1

HTMLページ内でのデプロイ, 5.3.5

パッケージ化, 5.3.4, 5.3.4

署名付きアプレット

ブラウザのセキュリティ, 5.3.2.2

オブジェクト署名証明書, 5.3.2.2

署名付きアプレットの使用方法, 5.3.2.2 ファイアウォールとともに使用, 5.3.3 ARCHIVE, APPLETタグのパラメータ, 5.3.5.3 ARRAY

クラス, 4.3.1

記述子, 4.3.1

オブジェクト, 作成, 4.3.1, 16.4.1

配列

定義, 16.1

取得, 16.4.2.6

名前付き, 16.1

コール可能文への引渡し, 16.4.3

結果セットからの取出し, 16.4.2.1

配列の一部の取出し, 16.4.2.5

型マップの使用, 16.5

操作, 16.1

認証(セキュリティ), 9.2 自動コミット, 2.3.8 自動コミット・モード

使用禁止, C.2.1

結果セットの動作, C.2.1

B

バッチ・ジョブ, ユーザーの認証, 9.9

バッチの更新，「バッチ更新」を参照

バッチ値

値の確認, 23.1.2.4

接続バッチ値, 設定, 23.1.2.2

接続値と文値, 23.1.2

デフォルト値, 23.1.2.1

値のオーバーライド, 23.1.2.5

文バッチ値, 設定, 23.1.2.3

BatchUpdateException, 23.1.3.7 beforeFirst()メソッド, 18.1.4 BFILE

クラス, 4.3.1

定義, 12.4

BFILEロケータ, 選択, 4.3.1 BigDecimalマッピング(属性に対して), 13.5.2 BLOB

クラス, 4.3.1

ロケータ

選択, 4.3.1

ブール型パラメータ, 制限事項, E.1.3 ブランチ修飾子(分散トランザクション), 29.2.5

C

CachedRowSet, 18.2

キャッシュ, クライアント側

スクロール可能な結果セットを実現するOracleの使用, 17.1

コール可能文

getOracleObject()メソッドの使用, 11.4.2

取消し

SQL文, E.1.5

戻り値のキャスト, 11.4.5 catalog引数(DatabaseMetaData), A.4.5 CHAR列

setFixedCHAR()の使用によるWHEREでの合致, 11.4.7.2

キャラクタ・セット, 4.4.3 チェックサム

コード例, 9.5.3

Javaでのパラメータの設定, 9.5.3

OCIドライバによるサポート, 9.5.1

Thinドライバによるサポート, 9.5.2

CLASSPATH環境変数, 指定, 2.2.2 clearBatch()メソッド, 23.1.3.5 clearDefines()メソッド, 23.2.3 CLOB

クラス, 4.3.1

ロケータ, 選択, 4.3.1

closeメソッド, 20.3.2, 20.3.2 close(), 20.1.3 close()メソッド, E.1.2

文のキャッシュ, 20.2.2, 20.2.3

closeWithKey(), 20.1.3 closeWithKey()メソッド, 20.2.4, 20.2.4 CMAN.ORAファイル, 作成, 5.3.2.1 CODE, APPLETタグのパラメータ, 5.3.5.1 CODEBASE, APPLETタグのパラメータ, 5.3.5.2 コレクション

定義, 16.1

コレクション(ネストした表と配列), 16.4.1 列型

定義, 23.2.3

再定義, 23.2

分散トランザクション・ブランチのコミット, 29.2.4 データベースの変更のコミット, 2.3.8 CONNECT /機能, 9.9 接続

クローズ, 2.3.9

オープン, 2.3.2

接続属性, 21.3 接続キャッシュ・プロパティ, 21.4 Connection Manager

インストール, 5.3.2.1

起動, 5.3.2.1

使用, 5.3.2.1

複数のマネージャの使用, 5.3.2.1

接続文字列の記述, 5.3.2.1

接続プロパティ, 8.1.5

put()メソッド, 8.1.9

接続文字列

Connection Manager, 5.3.2.1

接続

読取り専用, C.3

SQL型の定数, 4.5.5.7 CREATE TYPE文, 13.4.1 create()メソッド

ORADataFactoryインタフェース, 13.3.5

createSQLXML

XMLインスタンスを作成するメソッド, 3.3.2

createStatement(), 20.1.3 createStatement()メソッド, 20.2.4 createTemporary()メソッド, 14.5 CursorName

制限事項, A.4.1

カーソル, E.1.2 カスタム・コレクション・クラス

JPublisher, 16.6

定義, 16.1.1, 16.6

カスタムJavaクラス, 4.2.3

定義, 13.1

カスタム・オブジェクト・クラス

作成, 13.3

定義, 13.1

カスタム参照クラス

JPublisher, 15.4

定義, 15.1, 15.4

D

データ変換, 11.2

LONG, 12.2.2

LONG RAW, 12.2.1

データソース

作成と接続(JNDIを使用), 8.1.4

作成と接続(JNDIなし), 8.1.3

Oracleによる実装, 8.1.2

プロパティ, 8.1.2

標準インタフェース, 8.1.2

データ・ストリーム

回避, 12.2.4

データ型マッピング, 11.1 データ型

Java, 11.1

Javaネイティブ, 11.1

JDBC, 11.1

Oracle SQL, 11.1

データベース

接続

アプレットから, 5.3.1

複数のConnection Managerの経由, 5.3.2.1

サーバー側内部ドライバ, 7.2

接続テスト, 2.2.5 データベース指定子, 8.2 データベースURL

ユーザーIDとパスワードを含む, 2.3.2

データベースURL, 指定, 2.3.2 データベースURL

データベース指定子, 8.2

DatabaseMetaDataコール, A.4.5 DatabaseMetaDataクラス, A.3.2 データソース, 8.1

JNDI, 8.1.4

DATEクラス, 4.3.1 DBMS_SERVICE.SERVICE_TIME, 22.2 DBMS_SERVICE.THROUGHPUT, 22.2 JDBCプログラムのデバッグ, E.2 DEFAULT_CHARSETキャラクタ・セット値, 4.4.3 defaultConnection()メソッド, 7.2 defineColumnType()メソッド, 12.2.4, 23.2.3 分散トランザクションIDコンポーネント, 29.2.5 分散トランザクション

ブランチ修飾子, 29.2.5

同じリソース・マネージャのチェック, 29.2.4

トランザクション・ブランチのコミット, 29.2.4

コンポーネントおよびシナリオ, 29.1.1

概念, 29.1.2

分散トランザクションIDコンポーネント, 29.2.5

トランザクション・ブランチの終了, 29.2.4

実装例, 29.4

forget, 29.2.4

グローバル・トランザクション識別子, 29.2.5

IDフォーマット識別子, 29.2.5

リカバリ中のトランザクション・ブランチのリストの取得, 29.2.4

OracleのXA接続実装, 29.2.2

OracleのXAデータソース実装, 29.2.1

OracleのXA ID実装, 29.2.5

OracleのXA最適化, 29.3.4

OracleのXAリソース実装, 29.2.3

概要, 29.1

トランザクション・ブランチの準備, 29.2.4

トランザクション・ブランチのロールバック, 29.2.4

トランザクション・ブランチの起動, 29.2.4

トランザクション・ブランチIDコンポーネント, 29.2.5

XA接続インタフェース, 29.2.2

XAデータソース・インタフェース, 29.2.1

XAエラー処理, 29.3.3

XA例外クラス, 29.3.1

XA IDインタフェース, 29.2.5

XAリソース機能, 29.2.4

XAリソース・インタフェース, 29.2.3

DML RETURNING, 4.2.5, 4.6

例, 4.6.3

制限事項, 4.6.4

Oracle固有のAPI, 4.6.1

文の実行, 4.6.2

Double.NaN

使用上の制限事項, 4.3.1

driverType, 8.1.2

E

暗号化

コード例, 9.5.3

概要, 9.5

Javaでのパラメータの設定, 9.5.3

OCIドライバによるサポート, 9.5.1

Thinドライバによるサポート, 9.5.2

分散トランザクション・ブランチの終了, 29.2.4 Enterprise JavaBeans(EJB), 18.2 環境変数

指定, 2.2.2

エラー

一般JDBCメッセージ構造, D.1

一般JDBCメッセージ, リスト, D.2

例外の処理, 2.6

TTCメッセージ, リスト, D.4

例外

エラー・コードの取出し, 2.6

メッセージの取出し, 2.6

SQL状態の取出し, 2.6

execute()メソッド, 18.3 executeBatch()メソッド, 23.1.3.3 executeUpdate()メソッド, 23.1.2.7 明示的文キャッシュ

定義, 20.1.3

NULLデータ, 20.2.4

JDBCに対する拡張機能, Oracle, 4, 11, 13, 15, 16, 23 外部変更(結果セット)

定義, 17.6

可視性と検出, 17.6.1

外部ファイル

定義, 12.4

F

フェイルオーバー

高速接続, 27

高速接続フェイルオーバー, 27 高速接続フェイルオーバー

前提条件, 27.2.1

結果セットのフェッチ方向, 17.4.2 フェッチ・サイズ, 結果セット, 17.4 FilteredRowSet, 18.5 ファイナライザ・メソッド, E.1.2 ファイアウォール

アプレットに対する構成, 5.3.3.1

接続文字列, 5.3.3.2

説明, 5.3.3

必要な規則リストの項目, 5.3.3.1

アプレットとともに使用, 5.3.3

ファイアウォール, JDBCとともに使用, E.1.6 浮動小数点との互換性, A.4.4 Float.NaN

使用上の制限事項, 4.3.1

フォーマット識別子, トランザクションID, 29.2.5 freeTemporary()メソッド, 14.5, 14.5 ファンクション・コール構文, JDBCエスケープ構文, A.3.5

G

getARRAY()メソッド, 16.4.2.1

getArray()メソッド, 16.3.3, 16.4.2.2

型マップの使用, 16.4.2.4

getAttributes()メソッド

Structによる使用, 13.3.3.3

getAutoBuffering()メソッド

oracle.sql.ARRAYクラス, 16.3.2

oracle.sql.STRUCTクラス, 13.2.5

getBaseType()メソッド, 16.4.2.6 getBinaryStream()メソッド, 12.2.3 getBytes()メソッド, 4.3.1, 12.2.3 getCallWithKey, 20.1.3 getCallWithKey()メソッド, 20.2.4, 20.2.4 getColumns()メソッド, 23.2.4 getConcurrency()メソッド(結果セット), 17.2 getConnection()メソッド, 7.2, 24.4 getCursor()メソッド, 4.5.2, 4.5.2 getCursorName()メソッド

制限事項, A.4.1

getDefaultExecuteBatch()メソッド, 23.1.2.4 getErrorCode()メソッド(SQLException), 2.6 getExecuteBatch()メソッド, 23.1.2.3, 23.1.2.4 getFetchSize()メソッド, 17.4.1 getJavaSqlConnection()メソッド, 4.5.5.8 getMessage()メソッド(SQLException), 2.6 getNumericFunctions()メソッド, A.3.2 getObject()メソッド

戻り値のキャスト, 11.4.5

オブジェクト参照, 15.2.1

ORADataオブジェクト, 13.3.5

戻り型, 11.4.1, 11.4.3

Oracleオブジェクトの取出し, 13.2.2

ORADataインタフェースとの使用, 13.3.6

getObjectReturnsXMLType

getObjectMethodの戻り型を変更するプロパティ, 3.3.2

getOracleArray()メソッド, 16.4.2.2, 16.4.2.6 getOracleAttributes()メソッド, 13.2.2 getOracleObject()メソッド

戻り値のキャスト, 11.4.5

戻り型, 11.4.2, 11.4.3

コール可能文での使用, 11.4.2

結果セットでの使用, 11.4.2

getOraclePlsqlIndexTable()メソッド, 4.7.1, 4.7.3, 4.7.4

引数

int paramIndex, 4.7.4

コード例, 4.7.4 getORAData()メソッド, 13.3.5, 13.3.6 getPassword()メソッド, 8.1.2 getPlsqlIndexTable()メソッド, 4.7.1, 4.7.3, 4.7.3, 4.7.4, 4.7.4

引数

Class primitiveType, 4.7.4

int paramIndex, 4.7.4

コード例, 4.7.4, 4.7.4 getProcedureColumns()メソッド, 23.2.4 getProcedures()メソッド, 23.2.4 getSQLState()メソッド(SQLException), 2.6 getSQLTypeName()メソッド, 13.2.1, 16.4.2.6 getStatementCacheSize()メソッド

コード例, 20.2.1

getStatementWithKey(), 20.1.3 getStatementWithKey()メソッド, 20.2.4, 20.2.4 getString()メソッド, 4.4.3

ROWIDの取出し, 4.5.1

getStringFunctions()メソッド, A.3.2 getStringWithReplacement()メソッド, 4.4.3 getSystemFunctions()メソッド, A.3.2 getTimeDateFunctions()メソッド, A.3.2 getTransactionIsolation()メソッド, C.3 getType()メソッド(結果セット), 17.2 getTypeMap()メソッド, 13.3.3.1 getUpdateCounts()メソッド(BatchUpdateException), 23.1.3.7 getValue()メソッド

オブジェクト参照, 15.2.1

getXXX()メソッド

戻り値のキャスト, 11.4.5

特定のデータ型, 11.4.4

グローバル・トランザクション識別子(分散トランザクション), 29.2.5 グローバル・トランザクション, 29.1 グローバリゼーション, 19

使用, 19

H

HEIGHT, APPLETタグのパラメータ, 5.3.5.1

HTMLタグ, アプレットのデプロイ用, 5.3.5

I

IEEE 754浮動小数点との互換性, A.4.4

暗黙的接続キャッシュ, 21

例, 21.2.6

暗黙的文キャッシュ

定義, 20.1.2

最低使用頻度(LRU)アルゴリズム, 20.1.2

IN OUTパラメータ・モード, 4.7.3 INパラメータ・モード, 4.7.2 インストール

ディレクトリとファイル, 2.2.1

クライアントでの検証, 2.2

Instant Client機能, 6.5.1 整合性

コード例, 9.5.3

概要, 9.5

Javaでのパラメータの設定, 9.5.3

OCIドライバによるサポート, 9.5.1

Thinドライバによるサポート, 9.5.2

内部変更(結果セット)

定義, 17.6

isSameRM()(分散トランザクション), 29.2.4 isTemporary()メソッド, 14.5, 14.5

J

Java

コンパイルと実行, 2.2.3

データ型, 11.1

ネイティブなデータ型, 11.1

ストアド・プロシージャ, 2.5.2

ストリーム・データ, 12

Java Naming and Directory Interface(JNDI), 8.1.1 Javaソケット, 1.1.1 Java仮想マシン(JVM), 7.1 java.math, Java mathパッケージ, 2.3.1 java.sql, JDBCパッケージ, 2.3.1 java.sql.Connectionインタフェース

closeメソッド, 20.3.2

java.sql.SQLException()メソッド, 2.6 java.sql.Statementインタフェース

closeメソッド, 20.3.2

java.sql.Structクラス

getSQLTypeName()メソッド, 13.2.1

java.sql.Typesクラス, 23.2.3 java.util.Mapクラス, 16.4.2.5 java.util.Properties, 24.3 JDBC

IDE, 1.2.3

基本プログラム, 2.3

データ型, 11.1

定義, 1

パッケージのインポート, 2.3.1

Oracle拡張機能の制限事項, A.4

サンプル・ファイル, 2.2.3

テスト, 2.2.5

バージョンのサポート, 3

JDBC 2.0のサポート

データ型のサポート, 3.1.1

拡張機能のサポート, 3.1.3

概要, 3.1

JDK 1.2.xとJDK 1.1.x, 3.1, 3.2

標準機能のサポート, 3.1.2

JDBCドライバ

アプレット, 5.3

ニーズに合ったドライバの選択, 1.1.2

共通機能, 1.1.1

一般的な問題, E.1

ドライバのバージョン確認, 2.2.4

概要, 1.1

JDBCエスケープ構文, A.3

制限事項, E.1.3

JDBCエスケープ構文, A.3

ファンクション・コール構文, A.3.5

LIKEエスケープ文字, A.3.3

外部結合, A.3.4

スカラー関数, A.3.2

時刻および日付リテラル, A.3.1

SQLへの変換例, A.3.6

JDBCマッピング(属性に対して), 13.5.2 JdbcCheckupプログラム, 2.2.5 JDBCRowSet, 18.3 JDBCSpy, E.2.2 JDBCTest, E.2.2 JDeveloper, 1.2.3 JDK

サポートされるバージョン, 1.2.1

JNDI

データソース, 8.1.4

データソースの参照, 8.1.4

Oracleによるサポートの概要, 8.1.1

データソースの登録, 8.1.4

JoinRowSet, 18.6 JPublisher, 13.3.6, 13.5.1 JPublisherユーティリティ, 13.3

カスタム・コレクション・クラスの作成, 16.6

カスタムJavaクラスの作成, 13.5

カスタム参照クラスの作成, 15.4

SQL型のカテゴリとマッピング・オプション, 13.5.2

型マッピング・モードと設定, 13.5.2

型マッピング, 13.5.2

JVM, 7.1

K

KPRBドライバ

概要, 1.1.1

SQLエンジンとの関係, 7.1

セッション・コンテキスト, 7.3

テスト, 7.4

トランザクション・コンテキスト, 7.3

URL, 7.2

L

LD_LIBRARY_PATH環境変数, 指定, 2.2.2

LDAP

SSL, 8.2

最低使用頻度(LRU)アルゴリズム, 20.1.2, 24.3 libheteroxa11_g.so共有ライブラリ, 29.5.1 libheteroxa11.so共有ライブラリ, 29.5.1 LIKEエスケープ文字, JDBCエスケープ構文, A.3.3 setBytes()とsetString()の制限, 回避するためのストリームの使用, 12.7.2 ロード・バランシング・アドバイザ, 22.1 LOB

定義, 12.4

LONG

データ変換, 12.2.2

LONG RAW

データ変換, 12.2.1

LRUアルゴリズム, 20.1.2

M

make()メソッド, 4.4.3

メモリー・リーク, E.1.2

可変配列, 16.6

N

名前付き配列, 16.1

定義, 16.4.1

nativeXA, 8.1.2, 29.5.1 ネットワーク・イベント, トラップ, E.2.1 next()メソッド, 18.1.4 NLS。「グローバリゼーション」を参照 NLS_LANG変数

サポート対象外, 19

NULL

テスト, 11.2.3

NULLデータ

変換, 11.2.2

NULLデータ

明示的文キャッシュ, 20.2.4

NullPointerException

Double.NaNおよびFloat.NaNの変換時の発生, 4.3.1

NUMBERクラス, 4.3.1

O

オブジェクト参照

オブジェクト値のアクセス, 15.2.1, 15.3, 15.3

説明, 15.1

プリコンパイルされたSQL文への引渡し, 15.2.3

取出し, 15.2.1

コール可能文からの取出し, 15.2.2

オブジェクト値の更新, 15.2.1, 15.3, 15.3

オブジェクトJDBCマッピング(属性に対して), 13.5.2 OCIドライバ

説明, 1.1.1

ODBCSpy, E.2.2 ODBCTest, E.2.2 ONS

構成, 27.2.2

ons.configファイル, B.2.1.1, B.2.1.1 最適化, パフォーマンス, C.2 Oracle Advanced Security

JDBCによるサポート, 9.1

OCIドライバによるサポート, 9.1

Thinドライバによるサポート, 9.1

Oracle Connection Manager, 5.3.1 Oracleデータ型

使用, 11

Oracle拡張機能, 4.2

データ型のサポート, 4.2.2

制限事項, A.4

DatabaseMetaDataコールへのcatalog引数, A.4.5

CursorName, A.4.1

IEEE 754浮動小数点との互換性, A.4.4

JDBC外部結合エスケープ, A.4.2

PL/SQL表, BOOLEAN, レコード型, A.4.3

読取り専用接続, C.3

SQLWarningクラス, A.4.6

オブジェクトのサポート, 4.2.3 結果セット, 11.3 文, 11.3 JDBCに対する, 4, 11, 13, 15, 16, 23 Oracle JPublisher, 4.2.3

作成されたクラス, 13.4.2.3

Oracleマッピング(属性に対して), 13.5.2 Oracle Notification Service。「ONS」を参照 Oracleオブジェクト

JDBC, 13.1

ORADataインタフェースを使用した変換, 13.3.5

getObject()メソッドの取出し, 13.2.2

Javaクラスによるサポート, 13.2

カスタム・オブジェクト・クラスへのマッピング, 13.3

SQLDataインタフェースを使用したデータの読込み, 13.3.4

操作, 13.1

SQLDataインタフェースを使用したデータの書込み, 13.3.4

Oracle SQLデータ型, 11.1 OracleCallableStatementインタフェース, 4.5.5.4

getOraclePlsqlIndexTable()メソッド, 4.7.1

getPlsqlIndexTable()メソッド, 4.7.1

getXXX()メソッド, 11.4.4

registerIndexTableOutParameter()メソッド, 4.7.1, 4.7.3

registerOutParameter()メソッド, 11.4.7

setPlsqlIndexTable()メソッド, 4.7.1, 4.7.2

OracleCallableStatementオブジェクト, 20.1.2, 20.1.2 OracleConnectionクラス, 4.5.5.1 OracleConnectionインタフェース, 24.3 OracleConnectionオブジェクト, 20.1.1 OracleDatabaseMetaDataクラス, A.3.2 OracleDataSourceクラス, 8.1.2, 24.3, 24.3 oracle.jdbc.パッケージ, 4.5.5 oracle.jdbc, OracleのJDBC対応拡張機能, 2.3.1 oracle.jdbc.OracleCallableStatementインタフェース, 4.5.5.4 oracle.jdbc.OracleConnectionインタフェース, 4.5.5.1

getTransactionIsolation()メソッド, C.3

setTransactionIsolation()メソッド, C.3

oracle.jdbc.OraclePreparedStatementインタフェース, 4.5.5.3 oracle.jdbc.OracleResultSet, 11.3 oracle.jdbc.OracleResultSetインタフェース, 4.5.5.5 oracle.jdbc.OracleResultSetMetaDataインタフェース, 4.5.5.6, 11.5

使用, 11.5

oracle.jdbc.OracleSqlクラス, A.3.6 oracle.jdbc.OracleStatement, 11.3 oracle.jdbc.OracleStatementインタフェース, 4.5.5.2 oracle.jdbc.OracleTypesクラス, 4.5.5.7, 23.2.3 oracle.jdbc.poolパッケージ, 24.3 oracle.jdbc.xaパッケージおよびサブパッケージ, 29.1.4 OracleOCIConnectionクラス, 24.3 OracleOCIConnectionPoolクラス, 24, 24.3 OraclePreparedStatementインタフェース, 4.5.5.3

getOraclePlsqlIndexTable()メソッド, 4.7.1

getPlsqlIndexTable()メソッド, 4.7.1

registerIndexTableOutParameter()メソッド, 4.7.1

setPlsqlIndexTable()メソッド, 4.7.1, 4.7.2

OraclePreparedStatementオブジェクト, 20.1.2, 20.1.2 OracleResultSetインタフェース, 4.5.5.5

getXXX()メソッド, 11.4.4

OracleResultSetMetaDataインタフェース, 4.5.5.6 OracleServerDriverクラス

defaultConnection()メソッド, 7.2

oracle.sqlパッケージ

データ変換, 11.2

説明, 4.3.1

oracle.sql.ARRAYクラス, 16.1.1

NESTED TABLE, 4.3.1

VARRAY, 4.3.1

getAutoBuffering()メソッド, 16.3.2

Javaプリミティブ型用のメソッド, 16.3.1

setAutoBuffering()メソッド, 16.3.2

setAutoIndexing()メソッド, 16.3.3, 16.3.3

oracle.sql.BFILEクラス, 4.3.1 oracle.sql.BLOBクラス, 4.3.1 oracle.sql.CHARクラス

getString()メソッド, 4.4.3

getStringWithReplacement()メソッド, 4.4.3

toString()メソッド, 4.4.3

oracle.sql.CharacterSetクラス, 4.4.3 oracle.sql.CLOBクラス, 4.3.1 oracle.sql.データ型

サポート, 4.3.1

oracle.sql.DATEクラス, 4.3.1 oracle.sql.Datum配列, 4.7.4 oracle.sql.Datumクラス, 説明, 4.3.1 oracle.sql.NUMBERクラス, 4.3.1 oracle.sql.ORADataインタフェース, 13.3.5 oracle.sql.ORADataFactoryインタフェース, 13.3.5 OracleSql.parse()メソッド, A.3.6 oracle.sql.RAWクラス, 4.3.1 oracle.sql.REFクラス, 4.3.1 oracle.sql.ROWIDクラス, 4.5.1 oracle.sql.STRUCTクラス, 4.3.1

getAutoBuffering()メソッド, 13.2.5

setAutoBuffering()メソッド, 13.2.5

OracleStatementインタフェース, 4.5.5.2 OracleTypesクラス, 4.5.5.7 OracleTypesクラス(型コード用), 4.5.5.7 OracleTypes.CURSOR変数, 4.5.2 OracleXAConnectionクラス, 29.2.2 OracleXADataSourceクラス, 29.2.1 OracleXAResourceクラス, 29.2.3, 29.2.4 OracleXidクラス, 29.2.5 ORADataインタフェース, 4.2.3

その他の使用方法, 13.3.7

利点, 13.3.1

Oracleオブジェクト型, 13

データの読込み, 13.3.6

データの書込み, 13.3.6

orai18n.jarファイル, 19.1 OUTパラメータ・モード, 4.7.3, 4.7.3, 4.7.3 外部結合, JDBCエスケープ構文, A.3.4

P

パラメータ・モード

IN, 4.7.2

IN OUT, 4.7.3

OUT, 4.7.3, 4.7.3, 4.7.3

パスワード, 指定, 2.3.2 PATH環境変数, 指定, 2.2.2 PDA, 18.2 パフォーマンス拡張, 標準準拠とOracle, 3.1.4 パフォーマンス拡張要素

列型の定義, 23.2.3

TABLE_REMARKSレポート, 23.2.4

パフォーマンスの最適化, C.2 携帯情報端末(PDA), 18.2 PL/SQL

制限事項, E.1.3

ストアド・プロシージャ, 2.5.1

PL/SQL索引付き表, 4.7

マッピング, 4.7.3

スカラー・データ型, 4.7.1

PL/SQL型

対応するJDBC型, 4.7.1

制限事項, A.4.3

PoolConfig()メソッド, 24.3 populate()メソッド, 18.2 行のプリフェッチ, 23.2

推奨デフォルト値, 23.2.2

分散トランザクション・ブランチの準備, 29.2.4 prepareCall(), 20.1.3 prepareCall()メソッド, 20.2.3, 20.2.3, 20.2.3, 20.2.4 PreparedStatementオブジェクト

作成, 2.3.7

prepareStatement(), 20.1.3 prepareStatement()メソッド, 20.2.3, 20.2.3, 20.2.3, 20.2.4

コード例, 20.2.3

put()メソッド

プロパティ・オブジェクト, 8.1.9

型マップ, 13.3.3, 13.3.3.1

Q

問合せ, 実行, 2.3.4

R

RAWクラス, 4.3.1

リカバリ(分散トランザクション), 29.2.4

REFクラス, 4.3.1

REF CURSOR, 4.5.2

結果セット・オブジェクトとしてインスタンス化, 4.5.2

結果セットへの行の再フェッチ, 17.5 refreshRow()メソッド(結果セット), 17.5 registerIndexTableOutParameter()メソッド, 4.7.1, 4.7.3

引数

int elemMaxLen, 4.7.3

int elemSqlType, 4.7.3

int maxLen, 4.7.3

int paramIndex, 4.7.3

コード例, 4.7.3 registerOutParameter()メソッド, 11.4.7 remarksReportingフラグ, 23.2 Remote Method Invocation(RMI), 18.2 リソース・マネージャ, 29.1.1 結果セット

自動コミット・モード, C.2.1

メタデータ, 4.5.5.6

Oracle拡張機能, 11.3

getOracleObject()メソッドの使用, 11.4.2

結果セット拡張

ダウングレード・ルール, 17.2

フェッチ・サイズ, 17.4

制限事項, 17.2

Oracleスクロール可能性の要件, 17.1

Oracle更新可能性の要件, 17.1

行のプリフェッチ, 17.5

変更の可視性のサマリー, 17.6.2

外部変更の可視性と検出, 17.6.1

結果セット・フェッチ・サイズ, 17.4 結果セットの保持機能, 3.2.4 結果セット・オブジェクト

クローズ, 2.3.6

結果セット, 処理, 2.3.5 ResultSetクラス, 2.3.4 ResultSet()メソッド, 16.3.3 自動生成キーの取出し, 3.2.2 戻り型

getXXX()メソッド, 11.4.4.1

getObject()メソッド, 11.4.3

getOracleObject()メソッド, 11.4.3

戻り値

キャスト, 11.4.5

RMI, 18.2 分散トランザクション・ブランチのロールバック, 29.2.4 データベースの変更のロールバック, 2.3.8 行のプリフェッチ

データ・ストリーム, 12.7.3

ROWIDクラス

CursorNameメソッド, A.4.1

定義, 4.5.1

ROWID, 結果セット更新での使用, 17.1 RowSet

イベントおよびイベント・リスナー, 18.1.2

概要, 18.1

プロパティ, 18.1.1

横断, 18.1.4

実行時接続ロード・バランシング, 22

有効化, 22.2

実行される処理, 22.1

ロード・バランシング・アドバイザ, 22.1

概要, 22.1

S

セーブポイント

トランザクション, 3.2.1

スカラー関数, JDBCエスケープ構文, A.3.2 スキーマの命名, 4.2.4 スクリプト, ユーザーの認証, 9.9 スクロール可能な結果セット

フェッチ方向, 17.4.2

scroll-sensitivityの実装, 17.6.3

行のプリフェッチ, 17.5

外部変更の可視性と検出, 17.6.1

scroll-sensitive結果セット

制限事項, 17.2

セキュリティ

認証, 9.2

暗号化, 9.5

整合性, 9.5

Oracle Advanced Securityのサポート, 9.1

SELECT文

オブジェクト参照の取得, 15.2.1

sendBatch()メソッド, 23.1.2.5, 23.1.2.7 サーバー側内部ドライバ

データベースへの接続, 7.2

サーバー側Thinドライバ, 概要, 1.1.1 セッション・コンテキスト

KPRBドライバ, 7.3

setAutoBuffering()メソッド

oracle.sql.ARRAYクラス, 16.3.2

oracle.sql.STRUCTクラス, 13.2.5

setAutoCommit()メソッド, C.2.1 setAutoIndexing()メソッド, 16.3.3, 16.3.3 setBytes()の制限, 回避するためのストリームの使用, 12.7.2 setCursorNameメソッド, A.4.1 setDefaultExecuteBatch()メソッド, 23.1.2.2 setDisableStatementCaching()メソッド, 20.2.3 setEscapeProcessing()メソッド, A.3 setExecuteBatch()メソッド, 23.1.2.3 setFetchSize()メソッド, 17.4.1 setFixedCHAR()メソッド, 11.4.7.2 setMaxFieldSize()メソッド, 23.2.3 setNull(), 11.2.3 setNull()メソッド, 11.4.7 setObejct()メソッド, 11.4.6 setObject()メソッド

CustomDatumオブジェクト, 13.3.5

オブジェクト参照, 15.2.3

STRUCTオブジェクト, 13.2.4

オブジェクト・データの書込み, 13.3.6

setOracleObject()メソッド, 11.4.6 setORAData()メソッド, 13.3.5, 13.3.6 setPlsqlIndexTable()メソッド, 4.7.1, 4.7.2

引数

int curLen, 4.7.2

int elemMaxLen, 4.7.2

int elemSqlType, 4.7.2

int maxLen, 4.7.2

int paramIndex, 4.7.2, 4.7.4

Object arrayData, 4.7.2

コード例, 4.7.2 setPoolConfig()メソッド, 24.3 setREF()メソッド, 15.2.3 setRemarksReporting()メソッド, 23.2.4 setString()の制限, 回避するためのストリームの使用, 12.7.2 setString()メソッド

ROWIDとのバインド, 4.5.1

setTransactionIsolation()メソッド, C.3 setXXX()メソッド, 特定のデータ型, 11.4.7 署名付きアプレット, 5.3.1 Solaris

共有ライブラリ, 29.5.1

指定子

データベース, 8.2

SQL

Javaデータ型へのデータ変換, 11.2

型, 定数, 4.5.5.7

SQLエンジン

KPRBドライバとの関係, 7.1

SQL構文(Oracle), A.3 SQLDataインタフェース, 4.2.3

利点, 13.3.1

Oracleオブジェクト型, 13

Oracleオブジェクトからのデータの読込み, 13.3.4

Oracleオブジェクトからのデータの書込み, 13.3.4

SQLNET.ORA

トレースのためのパラメータ, E.2.1

SQLWarningクラス, 制限事項, A.4.6 SSL

LDAP, 8.2

分散トランザクション・ブランチの起動, 29.2.4 文キャッシュ

明示的

定義, 20.1.3

NULLデータ, 20.2.4

暗黙的

定義, 20.1.2

最低使用頻度(LRU)アルゴリズム, 20.1.2

Statementオブジェクト

クローズ, 2.3.6

作成, 2.3.3

statement.cancel(), E.1.5 文

Oracle拡張機能, 11.3

停止

文の実行, E.1.5

ストアド・プロシージャ

Java, 2.5.2

PL/SQL, 2.5.1

ストリーム・データ, 12

CHAR列, 12.3

クローズ, 12.6

例, 12.2.3

外部ファイル, 12.4

LOB, 12.4

LONG列, 12.2

LONG RAW列, 12.2

複数列, 12.5

注意, 12.7.1

RAW列, 12.3

行のプリフェッチ, 12.7.3

setBytes()とsetString()の制限を回避するための使用, 12.7.2

VARCHAR列, 12.3

ストリーム・データ列

バイパス, 12.5

STRUCTクラス, 4.3.1 STRUCTオブジェクト

埋込みオブジェクト, 13.2.2

取出し, 13.2.2

oracle.sql型としての属性の取出し, 13.2.2

SYS.ANYDATA, 4.5.4 SYS.ANYTYPE, 4.5.4

T

TABLE_REMARKS列, 23.2

TABLE_REMARKSレポート

制限事項, 23.2.4

TAF, 定義, 28.1 TCP/IPプロトコル, 8.2 テスト

NULL値, 11.2.3

Thinドライバ

アプレット, 5.3

SSLを介したLDAP, 8.2

概要, 1.1.1

サーバー側, 概要, 1.1.1

時刻および日付リテラル, JDBCエスケープ構文, A.3.1 tnsEntry, 8.1.2, 29.5.1 toDatum()メソッド

CustomDatumオブジェクトへの適用, 13.3.1, 13.3.5

setORAData()メソッドによるコール, 13.3.6

toJdbc()メソッド, 4.3.1 toString()メソッド, 4.4.3 トレース機能, E.2.1 トレース・パラメータ

クライアント側, E.2.1.1

サーバー側, E.2.1.2

トランザクション・ブランチ, 29.1 トランザクション・ブランチIDコンポーネント, 29.2.5 トランザクション・コンテキスト

KPRBドライバ, 7.3

トランザクションID(分散トランザクション), 29.1.2 トランザクション・マネージャ, 29.1.1 トランザクション・セーブポイント, 3.2.1 トランザクション

ローカルとグローバルの切替え, 29.1.3

透過的アプリケーション・フェイルオーバー(TAF), 定義, 28.1 TTCエラー・メッセージ, リスト, D.4 型マップ, 4.2.3, 11.4.1

エントリの追加, 13.3.3.1

STRUCT, 13.3.3.3

新しいマップの作成, 13.3.3.2

配列の使用, 16.4.2.4

配列の使用, 16.5

型マップ(SQLからJavaへ), 13.3 型マッピング

BigDecimalマッピング, 13.5.2

JDBCマッピング, 13.5.2

オブジェクトJDBCマッピング, 13.5.2

Oracleマッピング, 13.5.2

型マッピング

JPublisherオプション, 13.5.2

型マップ

データベース接続との関係, 7.2

型コード, Oracle拡張機能, 4.5.5.7

U

Unicodeデータ, 4.4.2

更新可能な結果セット

制限事項, 17.2

行のプリフェッチ, 17.5

更新の競合, 17.3

バッチ更新

概要, Oracleと標準モデル, 23.1.1

概要, サポートされている文, 23.1.1

バッチ更新(Oracleモデル)

バッチ値, 確認, 23.1.2.4

バッチ値, オーバーライド, 23.1.2.5

変更のコミット, 23.1.2.6

接続バッチ値, 設定, 23.1.2.2

接続バッチ値と文バッチ値, 23.1.2

デフォルト・バッチ値, 23.1.2.1

自動コミット無効化, 23.1.2

例, 23.1.2.7

制限事項と特徴, 23.1.2.1

概要, 23.1.2

文バッチ値, 設定, 23.1.2.3

ストリーム型不許可, 23.1.2.1

更新件数, 23.1.2.7

バッチ更新(標準モデル)

バッチへの追加, 23.1.3.2

バッチの消去, 23.1.3.5

変更のコミット, 23.1.3.4

エラー処理, 23.1.3.7

例, 23.1.3.6

バッチの実行, 23.1.3.3

バッチと非バッチの混在, 23.1.3.8

概要, 23.1.3

更新件数, 23.1.3.6

エラー時の更新件数, 23.1.3.7

結果セットでの更新の競合, 17.3 更新件数

Oracleバッチ更新, 23.1.2.7

標準バッチ更新, 23.1.3.6

エラー時(標準バッチ処理), 23.1.3.7

url, 8.1.2 URL

KPRBドライバ, 7.2

ユーザーID, 指定, 2.3.2

W

WebRowSet, 18.4

WIDTH, APPLETタグのパラメータ, 5.3.5.1

ウィンドウ, scroll-sensitiveな結果セット, 17.6.3

X

XA

接続実装, 29.2.2

接続(定義), 29.1.2

データソース実装, 29.2.1

データソース(定義), 29.1.2

定義, 29.1

エラー処理, 29.3.3

実装例, 29.4

例外クラス, 29.3.1

Oracle最適化, 29.3.4

OracleトランザクションID実装, 29.2.5

リソース実装, 29.2.3

リソース(定義), 29.1.2

トランザクションIDインタフェース, 29.2.5

XAException, 29.2.4 Xid, 29.2.4

Copyright © 1999, 2011, Oracle and/or its affiliates. All rights reserved.