Fusion Middleware Oracle WebLogic Server JDBCのプログラミング

11gリリース1 (10.3.6)

B60995-04(原本部品番号:E13726-05)

目次

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

はじめに

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

- 表記規則

1概要とロードマップ

- ドキュメントのスコープと対象読者

- このドキュメントの手引き

- 関連ドキュメント

- JDBCサンプルとチュートリアル

- Avitek Medical Recordsアプリケーション(MedRec)

- WebLogic Server配布キットのJDBCサンプル

- このリリースでの新機能と変更点

- DataDirectのOracleタイプ4 JDBCドライバ

- セキュアなRMIドライバ通信

- 非推奨

2アプリケーションでのWebLogic JDBCの使い方

- DataSourceオブジェクトからのデータベース接続の取得

- DataSourceオブジェクトにアクセスするパッケージのインポート

- DataSourceを使用したクライアント接続の取得

- 接続リクエスト失敗時に生じる可能性のある例外

- プールされた接続の制約

- アプリケーション・スコープのデータ・ソースからの接続の取得

3 JDBCアプリケーションのパフォーマンス・チューニング

- WebLogicのパフォーマンス向上機能

- プールされた接続の使用によるパフォーマンスの向上

- 文とデータのキャッシング

- ベスト・パフォーマンスのためのアプリケーション設計

- データをできるだけデータベースの内部で処理する

- 組込みDBMSセット・ベース処理を使用する

- 問合せを効率化する

- トランザクションを単一バッチにする

- DBMSトランザクションがユーザー入力に依存しないようにする

- 同位置更新を使用する

- 操作データをできるだけ小さくする

- パイプラインと並行処理を使用する

4 WebLogicブランドのDataDirectドライバの使用

- DataDirectのドキュメントの使用

- JDBC仕様の準拠

- インストール

- サポートされるドライバとデータベース

- WebLogic JDBCデータ・ソースを介した接続

- 独自のJDBCコードの開発

- 接続プロパティの指定

- IPアドレスの使用

- Javaセキュリティ・マネージャに必要なパーミッション

- MS SQLServerユーザーの場合

- MS SQLServer XA DLLのインストール

- MS SQLServerに対するinstjdbc.sqlの使用

5 WebLogicラッパー・ドライバの使い方

- WebLogic RMIドライバの使い方(非推奨)

- RMIドライバ・クライアントの相互運用性

- WebLogic RMIドライバのセキュリティ上の考慮事項

- WebLogic RMIドライバを使用するためのWebLogic Serverの設定

- RMIドライバを使用するサンプル・クライアント・コード

- 必要なパッケージをインポートする

- データベース接続を取得する

- JNDIルックアップを使用して接続を取得する

- WebLogic RMIドライバだけを使用してデータベース接続を取得する

- WebLogic RMIドライバによる行キャッシング

- WebLogic RMIドライバによる行キャッシングの重要な制限事項

- グローバル・トランザクション使用時の制限事項

- WebLogic JTSドライバの使い方(非推奨)

- JTSドライバを使用するサンプル・クライアント・コード

- WebLogic Poolドライバの使い方(非推奨)

6 JDBCドライバでのAPI拡張機能の使い方

- JDBCインタフェースのAPI拡張機能の使い方

- JDBCインタフェースのAPI拡張機能へのアクセス方法を示すサンプル・コード

- API拡張機能へアクセスするパッケージをインポートする

- 接続を取得する

- 接続をベンダーの接続としてキャストする

- API拡張機能を使用する

- Oracle JDBC型に対するAPI拡張機能の使用

- Oracle Thin Driverに対する非推奨のAPI拡張機能の使用

- Oracle Thin Driver拡張機能を使用する際の特別な考慮事項

- JDBCインタフェースのOracle Thin Driver拡張機能にアクセスするサンプル・コード

- ARRAYによるプログラミング

- WebLogic Oracle拡張機能へアクセスするパッケージをインポートする

- 接続を確立する

- ARRAYを取得する

- データベースでARRAYを更新する

- Oracle Array拡張機能メソッドを使用する

- STRUCTによるプログラミング

- STRUCTを取得する

- WebLogic OracleStruct拡張機能メソッドを使用する

- STRUCT属性を取得する

- STRUCTによってデータベース・オブジェクトを更新する

- データベース・オブジェクトを作成する

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

- REFによるプログラミング

- REFを取得する

- WebLogic OracleRef拡張機能メソッドを使用する

- 値を取得する

- REF値を更新する

- データベースでREFを作成する

- BLOBとCLOBを使用したプログラミング

- DBMSからBLOBロケータを選択する問合せを実行する

- WebLogic Server java.sqlオブジェクトを宣言する

- SQL例外ブロックを開始する

- プリペアド文を使用したCLOB値の更新

- さまざまなバージョンのWebLogic Serverクライアント/サーバー間におけるAPI拡張機能のサポート

- Oracle Thin Driverの拡張機能インタフェースとサポートされるメソッドの表

- Oracle Thin Driverでのバッチ処理の使用

- Oracle仮想プライベート・データベースを使用したプログラミング

- WebLogic ServerでのOracle VPDの使用

7 データ・ソースからの物理的な接続の取得

- 接続を開く

- 接続を閉じる

- 「影響のある接続の削除を有効化」がTrueの場合

- 「影響のある接続の削除を有効化」がFalseの場合

- 物理的な接続の使用に関する制限

8 WebLogic ServerにおけるRowSetの使い方

- RowSetについて

- RowSetの種類

- RowSetを使用したプログラミング

- CachedRowSet

- 特性

- CachedRowSetに特有のプログラミング上の考慮事項と制限

- RowSetの問合せ結果はすべてメモリーに格納される

- データの競合

- サンプル・コード

- CachedRowSetのクラスとインタフェースのインポート

- CachedRowSetの作成

- CachedRowSetのプロパティの設定

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

- CachedRowSetへの入力

- CachedRowSetへのメタデータの設定

- CachedRowSetのデータの操作

- RowSetの行からデータを取得する

- RowSetの行を更新する

- RowSetに行を挿入する

- RowSetの行を削除する

- RowSetの変更をデータベースとの間で同期する

- RowSetに対するデータベース更新用メタデータの設定

- メタデータを扱うためのWebLogic RowSet拡張

- executeAndGuessTableNameとexecuteAndGuessTableNameAndPrimaryKeys

- MetaDataインタフェースを使用した表および主キー情報の設定

- 書込み表の設定

- RowSetとトランザクション

- JTAグローバル・トランザクションとの統合

- グローバル・トランザクションを使用するRowSetの動作

- ローカル・トランザクションの使用

- ローカル・トランザクションを使用するRowSetの動作

- トランザクション完了後のWebLogic RowSetの再利用

- FilteredRowSet

- FilteredRowSetの特性

- 特有のプログラミング上の考慮事項

- RowSetフィルタは累積的ではない

- フィルタの設定、変更前に保留中の変更を解決する

- FilteredRowSetのサンプル・コード

- FilteredRowSetのクラスとインタフェースのインポート

- FilteredRowSetの作成

- FilteredRowSetのプロパティの設定

- FilteredRowSetのデータベース接続のオプション

- FilteredRowSetへの入力

- FilteredRowSetのメタデータの設定

- FilteredRowSetに対するフィルタの設定

- ユーザー定義のRowSetフィルタ

- WebLogic SQL方式フィルタ

- FilteredRowSetのデータの操作

- WebRowSet

- 特有のプログラミング上の考慮事項

- JoinRowSet

- JDBCRowSet

- SyncResolverを使用したSyncProviderExceptionの処理

- RowSetデータの同期における競合の種類

- SyncResolverのサンプル・コード

- SyncResolverオブジェクトの取得

- SyncResolverオブジェクト内の移動

- RowSetデータの同期の競合に対する解決後の値の設定

- 変更の同期

- WLCachedRowSet

- SharedRowSet

- SortedRowSet

- SQLPredicate、SQL方式のRowSetフィルタ

- SQLPredicateとは

- SQLPredicateの文法

- サンプル・コード

- オプティミスティックな同時実行性ポリシー

- VERIFY_READ_COLUMNS

- VERIFY_MODIFIED_COLUMNS

- VERIFY_SELECTED_COLUMNS

- VERIFY_NONE

- VERIFY_AUTO_VERSION_COLUMNS

- VERIFY_VERSION_COLUMNS

- オプティミスティックな同時実行性制御の制限

- オプティミスティックなポリシーの選択

- パフォーマンスのオプション

- JDBCのバッチ処理

- Oracle Databaseのバッチ処理の制限

- グループ削除

9 JDBCのトラブルシューティング

- UNIXでのOracle Database関連の問題

- UNIXでのスレッド関連の問題

- JDBCオブジェクトのクローズ

- JDBCオブジェクトの破棄

- Microsoft SQL Serverでのネストされたトリガーの使用

- ネスト・レベルの超過

- トリガーとEJBの使用

Oracle® Fusion Middleware

Oracle WebLogic Server JDBCのプログラミング

11gリリース1 (10.3.6)

B60995-04(原本部品番号:E13726-05)

2011年11月

このドキュメントは、Java Database Connectivity (JDBC) APIを使用するアプリケーションの開発とサポートを行うソフトウェア開発者およびシステム管理者向けに書かれています。また、WebLogic Serverを評価するビジネス・アナリストやシステム設計者にとって有用な情報も掲載しています。

Oracle Fusion Middleware Oracle WebLogic Server JDBCのプログラミング, 11gリリース1 (10.3.6)

B60995-04

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

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

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

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

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 Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標は許可の元に使用され、SPARC International, Incの商標または登録商標です。AMD、Opteron、AMDのロゴおよびAMD OpteronのロゴはAdvanced Micro Devicesの商標または登録商標です。UNIXはThe Open Groupの登録商標です。

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

はじめに

ここでは、このガイド『Oracle WebLogic Server JDBCのプログラミング』で使用されるアクセシビリティ機能および表記規則について説明します。

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

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

表記規則

このドキュメントでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

斜体

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

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

1概要とロードマップ

この章では、このガイド(『Oracle WebLogic Server JDBCのプログラミング』)の内容と構成について説明します。

- ドキュメントのスコープと対象読者

- このドキュメントの手引き

- 関連ドキュメント

- JDBCサンプルとチュートリアル

- このリリースでの新機能と変更点

ドキュメントのスコープと対象読者

このドキュメントは、Java Database Connectivity (JDBC) APIを使用するアプリケーションの開発とサポートを行うソフトウェア開発者およびシステム管理者向けに書かれています。また、WebLogic Serverを評価するビジネス・アナリストやシステム設計者にとって有用な情報も掲載しています。このドキュメントのトピックは、ソフトウェア・プロジェクトの評価、設計、開発、本番前、および本番段階に関連しています。

このドキュメントは、Java EEおよびEJBの概念に精通している読者を対象としています。このドキュメントでは、WebLogic Server EJBが提供する付加価値機能と、EJBアプリケーションを実行するWebLogic Server機能の使い方に関する主要な情報が重点的に扱われています。

このドキュメントの手引き

- この章第1章「概要とロードマップ」では、このドキュメントの構成を紹介します。

- 第2章「アプリケーションでのWebLogic JDBCの使い方」では、アプリケーションでJDBC接続を使用する方法について説明します。

- 第3章「JDBCアプリケーションのパフォーマンス・チューニング」では、アプリケーションでJDBC接続の使用法を最高のパフォーマンスが得られるように設計する方法について説明します。

- 第4章「WebLogicブランドのDataDirectドライバの使用」では、WebLogicブランドのDataDirectドライバをアプリケーションで使用する方法について説明します。

- 第5章「WebLogicラッパー・ドライバの使い方」では、データ・ソースからJDBC接続を取得するための一部の代替的なドライバの使用方法について説明します。

- 第6章「JDBCドライバでのAPI拡張機能の使い方」では、アプリケーションでサード・パーティ・ドライバをプログラミングする際の考慮事項について説明します。

- 第8章「WebLogic ServerにおけるRowSetの使い方」では、アプリケーションでRowSetを使用する方法について説明します。

- 第9章「JDBCのトラブルシューティング」では、JDBCの一般的な問題とソリューションについて説明します。

関連ドキュメント

このドキュメントでは、JDBC固有のプログラミングに関する情報を取扱います。

WebLogic Serverアプリケーションを開発、デプロイ、およびモニターするための包括的なガイドラインについては、以下のドキュメントを参照してください。

- 『Oracle WebLogic Server JDBCデータ・ソースの構成と管理』は、WebLogic ServerでのJDBCの構成および管理についてのガイドです。

- 『Oracle WebLogic Serverアプリケーションの開発』は、WebLogic Serverアプリケーションの開発ガイドです。

- 『Oracle WebLogic Serverへのアプリケーションのデプロイ』は、開発および本番環境でのWebLogic Serverアプリケーションのデプロイメントについての情報のプライマリ・ソースです。

JDBCサンプルとチュートリアル

このドキュメントの他にも、さまざまなJDBCサンプル・コードが用意されています。これらのサンプルでは、JDBCの構成とAPIの使い方、および主要なJDBC開発タスクを実行する実際的な手順が示されています。

Avitek Medical Recordsアプリケーション(MedRec)

MedRecはWebLogic Serverに付属したエンドツーエンドのサンプルJava EEアプリケーションであり、一元的で独立した医療記録管理システムをシミュレートします。MedRecアプリケーションには、患者、医師、および管理者に対して、さまざまなクライアントを使用して患者のデータを管理するフレームワークが用意されています。

MedRecはWebLogic ServerとJava EEの機能を例示し、Oracle推奨のベスト・プラクティスを重要点として示します。MedRecはWebLogic Server配布キットに含まれており、Windowsマシンの「スタート」メニューからアクセスできます。Linuxなどのプラットフォームでは、WL_HOME\samples\domains\medrecディレクトリからMedRecを起動します。WL_HOMEは、WebLogic Platformの最上位のインストール・ディレクトリです。

WebLogic Server配布キットのJDBCサンプル

WebLogic Serverでは、必要に応じてAPIサンプル・コードをWL_HOME\samples\domains\medrecディレクトリにインストールできます。WL_HOMEはWebLogic Serverの最上位インストール・ディレクトリです。WebLogic Serverのスタート・メニューからサンプル・サーバーを起動して、サンプルとその実行手順に関する情報を確認できます。

このリリースでの新機能と変更点

このリリースには、次の新しい機能と変更された機能が含まれています。

- DataDirectのOracleタイプ4 JDBCドライバ

- WebLogic RMIドライバのセキュリティ上の考慮事項

- 非推奨

WebLogic Serverのこのリリースに追加された新機能の一覧については、『Oracle WebLogic Serverの新機能』を参照してください。

DataDirectのOracleタイプ4 JDBCドライバ

DataDirectのOracleタイプ4 JDBCドライバは、WebLogicブランドのDataDirectドライバと呼ばれるようになりました。Oracle WebLogic Serverタイプ4 JDBCドライバのドキュメントは廃止され、DataDirectドライバに関する情報はオラクル社から提供されなくなりました。WebLogicブランドのドライバのWebLogic Server環境での構成方法と使用方法に関する情報は「WebLogicブランドのDataDirectドライバの使用」で引き続き提供されます。ドライバの動作の詳細は、DataDirectのドキュメントを確認することをお薦めします。http://www.datadirect.com/index.htmlで『Progress DataDirect for JDBC User's Guide Release 4.2』および『Progress DataDirect for JDBC Reference Release 4.2』を参照してください。

セキュアなRMIドライバ通信

RMIドライバ・クライアントとDataSourceオブジェクトとの通信は、「RMI JDBCセキュリティ」パラメータを設定することでサーバー・レベルで保護されます。「WebLogic RMIドライバのセキュリティ上の考慮事項」を参照してください。

非推奨

次のweblogic.jdbc.extensionsインタフェースと例外は、WebLogic Server 10.3.6.0で推奨されません。

- weblogic.jdbc.extensions.Driverinterceptor

- weblogic.jdbc.extensions.ConnectionDeadSQLEsception

- weblogic.jdbc.extensions.Connection UnavailableSQLEsception

- weblogic.jdbc.extensions.PoolDisabledSQLException

- weblogic.jdbc.extensions.PoolLimitSQLException

- weblogic.jdbc.extensions.PoolPermissionsSQLException

- weblogic.jdbc.extensions.PoolUnavailableSQLException

2アプリケーションでのWebLogic JDBCの使い方

この章では、WebLogic Server管理コンソールを使用して、JDBCデータ・ソース、マルチ・データ・ソースなどのWebLogic Serverの機能を有効化したり、構成やモニターを行ったりする方法について説明します。また、JMX APIとWebLogic Scripting Tool (WLST)を使用して、同じタスクをプログラム的に実行することもできます。構成後のJDBC接続コンポーネントは、アプリケーション内で使用できます。

以下の節では、アプリケーションでのJDBC接続の使用方法について説明します。

- DataSourceオブジェクトからのデータベース接続の取得

- プールされた接続の制約

- アプリケーション・スコープのデータ・ソースからの接続の取得

JDBCデータ・ソースおよびマルチ・データ・ソースの構成の詳細は、『Oracle WebLogic Server JDBCデータ・ソースの構成および管理』を参照してください。

DataSourceオブジェクトからのデータベース接続の取得

以下の節では、データ・ソース、マルチ・データ・ソースのそれぞれについて、DataSourceオブジェクトからデータベース接続を取得するように要求する方法を詳しく説明します。

- DataSourceオブジェクトにアクセスするパッケージのインポート

- DataSourceを使用したクライアント接続の取得

- 接続リクエスト失敗時に生じる可能性のある例外

DataSourceオブジェクトにアクセスするパッケージのインポート

アプリケーションでDataSourceオブジェクトを使用するには、以下のクラスをクライアント・コードにインポートします。

import java.sql.*;
import java.util.*;
import javax.naming.*;

DataSourceを使用したクライアント接続の取得

JDBCクライアント用に接続を取得するには、以下のコードに示すように、Java Naming and Directory Interface (JNDI)ルックアップを使用してDataSourceオブジェクトを見つけます。

注意:
クライアント側アプリケーションでJDBC接続を使用する際、サーバーとクライアントの両方のCLASSPATHに、同一のJDBCドライバ・クラスを指定する必要があります。ドライバ・クラスが一致していないと、java.rmi.UnmarshalException例外がスローされる場合があります。

Context ctx = null;
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL,
"t3://hostname:port");
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
ctx = new InitialContext(ht);
javax.sql.DataSource ds
= (javax.sql.DataSource) ctx.lookup ("myDataSource");
conn = ds.getConnection();
// You can now use the conn object to create
//  Statements and retrieve result sets:
stmt = conn.createStatement();
stmt.execute("select * from someTable");
rs = stmt.getResultSet();
...
//Close JDBC objects as soon as possible
stmt.close();
stmt=null;
conn.close();
conn=null;
}
catch (Exception e) {
// a failure occurred
log message;
}
finally {
try {
ctx.close();
} catch (Exception e) {
log message; }
try {
if (rs != null) rs.close();
} catch (Exception e) {
log message; }
try {
if (stmt != null) stmt.close();
} catch (Exception e) {
log message; }
try {
if (conn != null) conn.close();
} catch (Exception e) {
log message; }
}

(使用するWebLogic Serverに合わせて適切なhostnameとport番号に置き換えます)。

注意:
前述のコードでは、JNDIコンテキストを取得するために、使用可能な数件のプロシージャの1つが使用されています。JNDIの詳細は、『Oracle WebLogic Server JNDIのプログラミング』を参照してください。

接続リクエスト失敗時に生じる可能性のある例外

weblogic.jdbc.extensionsパッケージには、アプリケーション・リクエストの失敗時にスローされ得る以下の例外が含まれています。各例外は、java.sql.SQLExceptionの拡張です。

- ConnectionDeadSQLException - 予約された接続に対する接続テストに失敗したことが原因で、接続を取得するアプリケーション・リクエストが失敗すると生成されます。通常は、データベース・サーバーが利用できない場合に生じます。

- ConnectionUnavailableSQLException - 割り当てられるべきプール内に現在利用できる接続がなかったことが原因で、接続を取得するアプリケーション・リクエストが失敗すると生成されます。これは一時的なエラーであって、プール内の接続がすべて使用中の場合に生成されます。また、接続がテスト中であるために使用できない場合にもスローされることがあります。

- PoolDisabledSQLException - JDBCデータ・ソースが管理者によって無効にされたことが原因で、接続を取得するアプリケーション・リクエストが失敗すると生成されます。

- PoolLimitSQLException - HighestNumWaiters、ConnectionReserveTimeoutSecondsなどのデータ・ソースについて構成されたしきい値が原因で、接続を取得するアプリケーション・リクエストが失敗すると生成されます。

- PoolPermissionsSQLException - 接続を取得するアプリケーション・リクエストで、(セキュリティ)認証または認可チェックが失敗すると生成されます。

プールされた接続の制約

注意:
Oracle JDBC拡張機能や他のドライバから使用できる標準以外の方法の中には、接続の動作を永続的に(プールされた接続の後続のユーザーに継承される)変更するものがあります。WebLogic Serverでは、これらの呼出しの一部のタイプから可能なかぎり接続を保護しようとします。

データ・ソース内のプールされた接続を使用している場合に、DBMS固有のSQLコードが実行されることがあります。これはデータベース接続のプロパティを変更するものであり、WebLogic ServerおよびJDBCドライバからは認識されません。接続がデータ・ソースに返されたときに、その接続の特性の設定が有効な状態に戻らないことがあります。たとえばSybase DBMSで、「set rowcount 3 select * from y」などの文を使用すると、接続に対する後続の問合せでは最大で3行までしか返されません。接続がデータ・ソースに返されてから再利用された場合、選択対象の表に500の行があっても、接続の次のユーザーには引続き3行のみが返されます。

ほとんどの場合、同じ結果をもたらすことができる標準のJDBCコードが存在します。この例では、set rowcountの代わりにsetMaxRows()を使用できます。DBMS固有のSQLコードの代わりに標準のJDBCコードを使用することをお薦めします。標準のJDBC呼出しを使用して接続を変更すると、接続がデータ・ソースに返された時点で接続が標準の状態に戻ります。

接続を変更するDBMS固有のSQLコードを使用する場合は、接続をデータ・ソースに返す前に、その設定を受け入れ可能な状態に戻す必要があります。

アプリケーション・スコープのデータ・ソースからの接続の取得

アプリケーション・スコープのデータ・ソースから接続を取得するには、『Oracle WebLogic Server JDBCデータ・ベースの構成および管理』のパッケージ化されたJDBCモジュールからのデータベース接続の取得に関する項を参照してください。

3 JDBCアプリケーションのパフォーマンス・チューニング

この章では、JDBCアプリケーションのパフォーマンスを最適にするためのWebLogic Serverの設計方法および構成方法について説明します。

- WebLogicのパフォーマンス向上機能

- ベスト・パフォーマンスのためのアプリケーション設計

WebLogicのパフォーマンス向上機能

WebLogicには、JDBCアプリケーションのパフォーマンスを向上させるための機能がいくつか用意されています。

プールされた接続の使用によるパフォーマンスの向上

DBMSへのJDBC接続の確立には非常に時間がかかる場合があります。使用するアプリケーションでデータベース接続のオープンとクローズを繰り返す必要がある場合、これは重大なパフォーマンスの問題となります。WebLogicデータ・ソース内の接続プールを使用すると、こうした問題を効果的に解決できます。

WebLogic Serverを起動すると、データ・ソース内の接続が開き、すべてのクライアントで使用できるようになります。クライアントでデータ・ソースからの接続をクローズすると、その接続はプールに戻され、他のクライアントで使用できる状態になります。つまり、接続そのものはクローズされません。プールされた接続は、ほとんど負荷を生じることなくオープンしたりクローズしたりできます。

文とデータのキャッシング

DBMSのアクセスではリソースが大量に消費されます。プログラムでPrepared StatementまたはCallable Statementを再利用する場合、または複数のアプリケーションでの共有や、各接続どうしでの存続が可能な頻繁に使用するデータにアクセスする場合は、以下を使用してデータをキャッシュできます。

- 文キャッシュ(データ・ソース用)

- 読取り専用エンティティBean

- クラスタ環境でのJNDI

ベスト・パフォーマンスのためのアプリケーション設計

データベース・アプリケーションのパフォーマンスの良し悪しはほとんどの場合、アプリケーション言語ではなく、アプリケーションがどのように設計されているかによって決定されます。クライアントの数と場所、DBMS表および索引のサイズと構造、および問合せの数とタイプは、すべてアプリケーションのパフォーマンスに影響を与えます。

以下では、すべてのDBMSに当てはまる一般的なヒントを示します。また、アプリケーションで使用する特定のDBMSのドキュメントによく目を通しておくことも重要です。

データをできるだけデータベースの内部で処理する

DBMSアプリケーションのパフォーマンスに関する最も深刻な問題は、生データを不必要に移動することから発生します。これは、生データをネットワーク上で移動する場合にも、単にDBMSのキャッシュに出し入れする場合にも言えることです。こうした無駄を最小限に抑えるための良い方法は、クライアントがDBMSと同じマシンで動作している場合でも、ロジックをクライアントではなくデータの格納場所、つまりDBMSに置くことです。実際のところ、一部のDBMSでは、1個のCPUを共有するファット・クライアントとファットDBMSはパフォーマンスの致命的な低下をもたらします。

大部分のDBMSは、ストアド・プロシージャという、データの格納場所にロジックを置くための理想的なツールを備えています。ストアド・プロシージャを呼び出して10個の行を更新するクライアントと、同じ行を取得および変更し、UPDATE文を送信してその変更をDBMSに保存するクライアントの間には、パフォーマンスに大きな違いがあります。

また、DBMSのドキュメントを参照して、DBMS内のキャッシュ・メモリーの管理について調べる必要もあります。一部のDBMS (Sybaseなど)は、DBMSに割り当てられた仮想メモリーを分割し、特定のオブジェクトがキャッシュの固定領域を独占的に使用できるようにする機能を備えています。この機能を使用すると、重要な表または索引をディスクから一度読み出しておくことで、ディスクに再度アクセスしなくてもすべてのクライアントがそれらを使用できるようになります。

組込みDBMSセット・ベース処理を使用する

SQLは、セット処理言語です。DBMSは、完全にセット・ベース処理を行うように設計されています。データベースの1行へのアクセスは、例外なくセット・ベースの処理より遅く、またDBMSによっては実装が不完全です。たとえば、従業員100名に関するデータが格納されている4つの表がある場合、全従業員について各表を一度に更新する方が、従業員1名ごとに各表を100回更新するより常に高速です。

あまりに複雑すぎて1行ずつ処理する以外に方法がないと考えられていた処理の多くが、セット・ベースの処理に書き換えられ、パフォーマンスの向上を実現しています。たとえば、ある有名な給与管理アプリケーションは、巨大で低速なCOBOLアプリケーションから、連続実行される4つのストアド・プロシージャに変換されました。この結果、マルチCPUマシンで何時間もかかった処理が、より少ないリソースで15分で実行できるようになりました。

問合せを効率化する

ユーザーからよく尋ねられる質問に、「特定の結果セットで返される行数はどのくらいか」というものがあります。すべての行を取り出さずに調べる唯一の方法は、次のようにcountキーワードを使用して同じ問合せを発行することです。

SELECT count(*) from myTable, yourTable where ...

これにより、関連するデータには変更がなかった場合に、オリジナルの問合せが戻すべき行数が返されます。また関連するデータに影響を与えるその他のDBMSアクティビティが起きた場合に、問合せを実行すれば、実際の行数は変わります。

ただし、これはリソースを大量に消費する処理であることに注意してください。元の問合せによっては、DBMSは行を送信するのと同じくらいの処理を行って行をカウントする必要があります。

アプリケーションの問合せは、実際にどのようなデータが必要なのかをできる限り具体的に指定する必要があります。たとえば、まず一時表に抽出し、カウントだけを返し、次に限定された2番目の問合せを送信して一時表内の行のサブセットだけを返すようにします。

クライアントが本当に必要なデータだけを抽出することが、きわめて重要です。ISAM (リレーショナル・データベース以前のアーキテクチャ)から移植された一部のアプリケーションでは、実際に必要なのは最初の数行だけであっても、表内のすべての行を選択する問合せが送信されます。また、最初に取得する行を得るために「sort by」句を使用するアプリケーションもあります。このようなデータベース問合せは、パフォーマンスを不必要に低下させます。

SQLを適切に使用すると、こうしたパフォーマンス上の問題を回避できます。たとえば、高額給与の社員のうち上位3人だけのデータが必要な場合、問合せを適切に行うには相関サブ問合せを使用します。表3-1に、次のSQL文で返される表全体を示します。

select * from payroll

表3-1返されたすべての結果

名前

給与

Joe

10

Mike

20

Sam

30

Tom

40

Jan

50

Ann

60

Sue

70

Hal

80

May

80

相関サブ問合せ

select p.name, p.salary from payroll p
where 3 >= (select count(*) from payroll pp
where pp.salary >= p.salary);

表3-2に示すように、この問合せでは、より絞り込まれた結果が返されます。

表3-2サブ問合せの結果

名前

給与

Sue

70

Hal

80

May

80

この問合せでは、上位3名の高所得者の名前と給与が登録された3行だけが返されます。この問合せでは、給与表全体をスキャンし、次に各行について内部ループで給与表全体を再スキャンして、ループの外でスキャンした現在の行より高額の給与が何件あるかを調べます。この処理は複雑なように見えるかもしれませんが、DBMSはこの種の処理ではSQLを効率的に使用するように設計されています。

トランザクションを単一バッチにする

可能な限り、一連のデータ処理を収集し、更新トランザクションを次のような単一の文で発行してください。

BEGIN TRANSACTION
UPDATE TABLE1...
INSERT INTO TABLE2
DELETE TABLE3
COMMIT

この方法により、別個の文とコミットを使用するよりもパフォーマンスが向上します。バッチ内で条件ロジックと一時表を使用する場合でも、DBMSはさまざまな行と表に必要なすべてのロックを取得し、ワン・ステップで使用および解放するので、この方法は望ましいと言えます。別個の文とコミットを使用すると、クライアントとDBMS間の転送が増加し、DBMS内のロック時間が長くなります。こうしたロックにより、他のクライアントはそのデータにアクセスできなくなり、複数の更新がさまざまな順序で表を更新できるかによって、デッドロックが発生する可能性があります。

警告 :一意キー制約の違反などによって上記のトランザクション中の任意の文が適切に実行されなかった場合は、条件SQLロジックを追加して文の失敗を検出し、トランザクションをコミットせずにロールバックする必要があります。上の例の場合、INSERT文が失敗すると、ほとんどのDBMSは挿入の失敗を示すエラー・メッセージを返しますが、2番目と3番目の文の間でメッセージを取得したかのように動作して、コミットが行われてしまいます。Microsoft SQL Serverには、SQL set xact_abort onの実行によって有効となる接続オプションがあります。このオプションを使用すると、文が失敗した場合にトランザクションが自動的にロールバックされます。

DBMSトランザクションがユーザー入力に依存しないようにする

アプリケーションで、「BEGIN TRAN」と、更新のために行または表をロックするSQLを送信する場合、ユーザーのキー入力がなければトランザクションをコミットできないようにアプリケーションを設計することは避けます。ユーザーがキー入力をせずに昼食に出かけてしまうと、ユーザーが戻ってくるまでDBMS全体がロックされてしまいます。

トランザクションの作成と完了にユーザー入力が必要な場合は、オプティミスティック・ロックを使用します。簡単に言えば、オプティミスティック・ロックでは問合せと更新でタイムスタンプとトリガーが使用されます。問合せは、トランザクション中にデータをロックすることなく、タイムスタンプ値を持つデータを選択し、そのデータに基づいてトランザクションを準備します。

更新トランザクションがユーザー入力によって定義されると、そのデータはタイムスタンプと共に単一の送信として送られます。これにより、そのデータが最初に取り出したデータと同じであることを確認できます。トランザクションが正常に実行されると、変更されたデータのタイム・スタンプが更新されます。別のユーザーからの更新トランザクションによって現在のトランザクションが処理するデータが変更された場合、タイム・スタンプが変更され、現在のトランザクションは拒否されます。ほとんどの場合、関連データが変更されることはないので通常トランザクションは正常に実行されます。あるトランザクションが失敗すると、アプリケーションは更新されたデータをリフレッシュし、必要に応じてトランザクションを再作成するよう通知します。

同位置更新を使用する

データ行の同位置での更新は、行の移動より非常に高速です。行の移動は、更新処理で表設計の許容範囲を超えるスペースが必要な場合に行う必要があります。必要なスペースを持つ行を最初から設計しておけば、更新は早くなります。ただし、表に必要なディスク空間は大きくなります。ディスク・スペースのコストは低いので、パフォーマンスが向上するのであれば、使用量を少しだけ増やすことは価値ある投資だと言えるでしょう。

操作データをできるだけ小さくする

アプリケーションによっては、操作データを履歴データと同じ表に格納するものもあります。時間の経過と共に履歴データが蓄積されていくと、すべての操作問合せでは、新しいデータを取得するために(日々の作業では)役に立たないデータを大量に読み取らなければなりません。これを回避するには、過去のデータを別の表に移動し、まれにしか発生しない履歴問合せのためにこれらの表を結合します。これを行うことができない場合、最も頻繁に使用されるデータが論理的および物理的に配置されるよう、表を索引処理およびクラスタリングします。

パイプラインと並行処理を使用する

DBMSは、さまざまな作業を大量に処理するときに最も能力を発揮します。DBMSの最も不適切な使い方は、1つの大規模なシングル・スレッド・アプリケーション用のダム・ファイル・ストレージとして使用することです。容易に区別できる作業サブセットを扱う大量の並行処理をサポートするようアプリケーションとデータを設計すれば、そのアプリケーションはより高速になります。処理に複数のステップがある場合、先行ステップが完了するまで次のステップを待つのではなく、いずれかの先行ステップが処理を終えた部分のデータに対して後続ステップが処理を開始できるようにアプリケーションを設計します。これは常に可能であるとは限りませんが、このことに留意してプログラムを設計すると、パフォーマンスを大幅に向上させることができます。

4 WebLogicブランドのDataDirectドライバの使用

この章では、WebLogic Serverインストールに含まれているWebLogicブランドのDataDirectドライバについて説明します。

- DataDirectのドキュメントの使用

- JDBC仕様の準拠

- インストール

- サポートされるドライバとデータベース

- WebLogic JDBCデータ・ソースを介した接続

- 独自のJDBCコードの開発

- 接続プロパティの指定

- IPアドレスの使用

- Javaセキュリティ・マネージャに必要なパーミッション

- MS SQLServerユーザーの場合

DataDirectのドキュメントの使用

オラクル社では、DB2、Informix、MS SQL ServerおよびSybase向けにWebLogicブランドのDataDirectドライバを提供します。WebLogicブランドのDataDirectドライバをWebLogic Server環境で構成して使用する方法については、後続の項を参照してください。これらのドライバの詳細は、http://www.datadirect.com/index.htmlで『Progress DataDirect for JDBC User's Guide Release 4.2』および『Progress DataDirect for JDBC Reference Release 4.2』を参照してください。DataDirectのドキュメントを使用する場合、必要に応じて次のように読み替える必要があります。

- URL: "datadirect"のかわりに"weblogic"を使用

- インストール・ディレクトリ: WebLogicブランドのDataDirectドライバの完全修飾インストール・ディレクトリは、WL_HOME\server\libです。

JDBC仕様の準拠

WebLogicブランドのData DirectドライバはJDBC 4.0仕様に準拠しています。

注意:
様々なベンダーのドライバ使用時のWebLogic Server動作を比較したとき、ドライバがJDBCに準拠していても、ベンダーが異なる仕様と解釈したり特定の状況に対して異なる実装を提供したりする可能性があることを忘れないようにしてください。
たとえば、WebLogicブランドのSQL Serverドライバを使用する場合、TINYINT列(スキーマは範囲を0から256と定義)に負の値(-100)を入力すると、このドライバは例外をスローします。ところが、Microsoft SQL Serverドライバは負の記号を無視します。

インストール

WebLogicブランドのDataDirectドライバは、WebLogic ServerとともにWL_HOME\server\libフォルダにインストールされます。WL_HOMEはWebLogic Serverのインストール先ディレクトリです。ドライバ・クラス・ファイルはweblogic.jarのマニフェスト・クラスパスに含まれているので、ドライバは自動的にサーバーのクラスパスに追加されます。

注意:
WebLogic Serverの完全インストールを実行すると、WebLogicブランドのDataDirectドライバがデフォルトでインストールされます。カスタム・インストールを選択した場合は、WebLogic JDBCドライバ・オプションが選択されている(チェック・ボックスがオンになっている)ことを確認してください。このオプションが選択されていない場合、ドライバはインストールされません。

WebLogicブランドのDataDirectドライバはWebLogicのクライアントjarファイル(wlclient.jarなど)のマニフェスト・クラスパスには含まれていません。WebLogicクライアントでドライバを使用するには、以下のファイルをクライアントにコピーし、クライアントのクラスパスに追加する必要があります。

- DB2の場合: wldb2.jar

- Informixの場合: wlinformix.jar

- MS SQL Serverの場合: wlsqlserver.jar

- Sybaseの場合: wlsybase.jar

サポートされるドライバとデータベース

ドライバとデータベースのサポートの詳細は、http://www.oracle.com/technetwork/middleware/ias/downloads/fusion-certification-100350.htmlを参照してください。

WebLogic JDBCデータ・ソースを介した接続

WebLogic Server構成にJDBCデータ・ソースを作成し、このJDBCドライバを選択してデータ・ソース内に物理的なデータベース接続を作成します。それによって、アプリケーションがJNDIツリーでデータ・ソースをルック・アップして、接続を要求できるようになります。

関連情報については、以下を参照してください。

- WebLogic ServerのJDBCおよびデータ・ソースの詳細は、『Oracle WebLogic Server JDBCデータ・ソースの構成と管理』を参照してください。

- データ ソースからの接続のリクエストについては、『Oracle WebLogic Server JDBCのプログラミング』のDataSourceを使用したクライアント接続の取得に関する項を参照してください。

独自のJDBCコードの開発

コードがWebLogic Serverのクラスパス/環境で実行される場合、WebLogicブランドのDataDirectドライバを使用する独自のJDBCコードを開発して使用できます。

接続プロパティの指定

データ・ソースの接続の接続プロパティは、WebLogic Server管理コンソール、コマンド・ライン・インタフェース、またはJMX APIを使用して指定します。接続プロパティはDBMSによって異なります。各WebLogicブランドのDataDirectドライバに固有の接続プロパティのリストについては、『Progress DataDirect for JDBC User's Guide』の各ドライバの「Connection Properties」の項を参照してください。

IPアドレスの使用

WebLogicブランドのDataDirectドライバでは、『Progress DataDirect for JDBC User's Guide Release 4.2.』(http://www.datadirect.com/index.html)に記載されているように、IPv4形式およびIPv6形式のInternet Protocol (IP)アドレスがサポートされます。WebLogic環境では、単に、URLのjdbc:datadirect部分をjdbc:weblogicに変更します。たとえば、次の接続URLでは、IPv4形式でサーバーを指定しています。

jdbc:weblogic:db2://123.456.78.90:50000;DatabaseName=jdbc;User=test; Password=secret

Javaセキュリティ・マネージャに必要なパーミッション

Javaセキュリティ・マネージャを有効にした状態でWebLogicブランドのDataDirectドライバを使用する場合は、ドメインのセキュリティ・ポリシー・ファイルに特定のパーミッションを設定する必要があります。WebLogic Serverには、編集および使用可能なサンプル・セキュリティ・ポリシー・ファイルが用意されています。このファイルは、WL_HOME\server\lib\weblogic.policyにあります。weblogic.policyファイルには、ドライバに必要なほとんどすべてのパーミッションが含まれています。

weblogic.policyファイルを変更せずに使用する場合は、それ以上のパーミッションを付与する必要はありません。別のセキュリティ・ポリシー・ファイルを使用する場合や、追加のパーミッションを必要とするドライバ機能を使用する場合は、『Progress DataDirect for JDBC User's Guide Release 4.2』(http://www.datadirect.com/index.html)を参照してください。install_dirとしてWL_HOME/server(WL_HOMEはWebLogic Serverをインストールしたディレクトリ)を使用します。

WebLogic ServerでJavaセキュリティ・マネージャの使用の詳細は、『Oracle WebLogic Serverセキュリティのプログラミング』のJavaセキュリティを使用したWebLogicリソースの保護に関する項を参照してください。

MS SQLServerユーザーの場合

この項では、DataDirect MS SQL Serverドライバと組み合せて使用するためのMS SQLServerの構成に関する追加情報を示します。

- MS SQLServer XA DLLのインストール

- MS SQLServerに対するinstjdbc.sqlの使用

MS SQLServer XA DLLのインストール

WebLogic Serverには、MS SQL Server用に次のXA dllが用意されています。

- sqljdbc.dll: 32ビットWindows用

- 64sqljdbc.dll: 64ビットWindows用

- X64sqljdbc.dll: X64プロセッサ用

インストールするには、次のようにします。

1. WL_HOME\server\libディレクトリに移動します。

2. 場合に応じて次ようにします。

- 32ビットWindowsシステムの場合、sqljdbc.dllファイルをインストールします。

- 64ビットWindowsシステムの場合、64sqljdbc.dllファイルをコピーして名前をsqljdbc.dllに変更し、sqljdbc.dllファイルをインストールします。

- X64プロセッサの場合、X64sqljdbc.dllファイルをコピーして名前をsqljdbc.dllに変更し、sqljdbc.dllファイルをインストールします。

MS SQLServerに対するinstjdbc.sqlの使用

バージョン2008以上のMS SQLServerにストアド・プロシージャをインストールするDataDirectのinstjdbc.sqlスクリプトの一部のバージョンに、既知の問題があります。これを回避する方法は、instjdbc.sqlスクリプト内のdump tran master with no_logのすべてのインスタンスをDBCC SHRINKFILE(mastlog, 1)に置き換えることです。

5 WebLogicラッパー・ドライバの使い方

この章では、非推奨のWebLogicラッパー・ドライバとWebLogic Serverを組み合せて使用する方法について説明します。

注意:
新しいアプリケーションでは、DataSourceオブジェクトを使ってデータベース接続を取得することをお薦めします。DataSourceオブジェクト(WebLogicデータ・ソースおよびマルチ・データ・ソース)をJNDIツリーと一緒に使用して、データ・ソース内のプールされた接続にアクセスしてデータベース接続を取得できます。WebLogicラッパー・ドライバは非推奨になっています。JDBC 1.x APIを使用した既存のアプリケーションまたはレガシー・アプリケーションの場合は、WebLogicラッパー・ドライバを使用してデータベース接続を取得できます。

- WebLogic RMIドライバの使い方(非推奨)

- WebLogic JTSドライバの使い方(非推奨)

- WebLogic Poolドライバの使い方(非推奨)

WebLogic RMIドライバの使い方(非推奨)

注意:
RMIドライバ・クライアント機能は非推奨で、将来のリリースで削除される予定です。このリリースで導入されたWLConnectionおよびWLDataSourceの機能はRMIドライバ・クライアントでサポートされません。『Oracle WebLogic Server JDBCのプログラミング』のこのリリースの新規および変更されたJDBCデータ・ソース機能に関する項を参照してください。

RMIドライバ・クライアントは、DataSourceオブジェクトをルックアップすることで、DBMSへの接続を確立します。このルックアップは、Java Naming and Directory Interface (JNDI)ルックアップを使うか、またはクライアントに代わってJNDIルックアップを実行するWebLogic Serverを直接呼び出すことにより実行されます。

RMIドライバは、WebLogic t3ドライバ(非推奨)とPoolドライバ(非推奨)の機能に取って代わるもので、独自のt3プロトコルではなくJava標準のRemote Method Invocation (RMI)を使用してWebLogic Serverに接続します。

RMI実装の詳細はドライバによって自動的に処理されるため、WebLogic JDBC/RMIドライバを使用するためにRMIの知識は必要ではありません。

RMIドライバ・クライアントの相互運用性

以前のリリースのWebLogic Serverとの相互運用性には制限があります。参加(クライアント/サーバーまたはサーバー・ツー・サーバー)できるのは、同じメジャー・リリースのもののみです。以前の10.xクライアントは、ucp.jarをCLASSPATHに追加することで、以降のリリースやパッチ・セットと相互運用するよう更新できます。

WebLogic RMIドライバのセキュリティ上の考慮事項

WebLogic Server 10.3.2.0以前、RMIドライバ・クライアントではDataSourceオブジェクトへの非認可のRMIアクセスが可能でした。クライアントで、制御されていないデータベースへのアクセスが可能になるため、セキュリティの脆弱性が潜在することになります。これらの環境では、RMIドライバ・クライアントをWebLogicデータ・ソースおよびマルチ・データ・ソースと置き換えるか、RMIドライバ・クライアントが使用される場合は強力なネットワーク・セキュリティを実装することをお薦めします。

WebLogic Server 10.3.2.0以上のドメインのサーバーの場合、DataSourceオブジェクトへのRMIアクセスは、weblogic.jdbc.remoteEnabledシステム・プロパティによってサーバー・レベルで制御されます。デフォルトでは無効です。RMIドライバ・クライアントでDataSourceオブジェクトにアクセスできるようにするには、weblogic.jdbc.remoteEnabledプロパティの値をtrueに設定します。RMIドライバ・クライアントをWebLogicデータ・ソースおよびマルチ・データ・ソースと置き換えるか、RMIドライバ・クライアントが使用される場合は強力なネットワーク・セキュリティを実装することをお薦めします。

注意:
weblogic.jdbc.remoteEnabledシステム・プロパティは、WebLogic Server 10.3.6.0では推奨されません。

WebLogic Server 10.3.6.0以上のドメインのサーバーの場合、「RMI JDBCセキュリティ」パラメータを「セキュア」に設定することで、RMIドライバ・クライアントとDataSourceオブジェクトとの通信をサーバー・レベルで保護できます。

有効な値は次のとおりです。

- セキュア: リモート・クライアントおよびサーバーによるRMIを介した受信JDBC呼出しはすべて無効です。すべての受信JDBC呼出しではJTSが使用され、管理者認証されます。匿名などのその他のサブジェクトはすべて拒否されます。このオプションには、次のいずれかが必要です。

- ドメイン内通信の場合: 構成済SSLリスニング・ポート。

- ドメイン間通信の場合: 参加するドメイン間の構成済クロスドメイン・セキュリティ。『Oracle WebLogic Serverの保護』のWebLogic Serverドメイン間のクロス・ドメイン・セキュリティの有効化に関する項を参照してください。

セキュリティが構成されていない場合、すべての操作が例外で失敗します。

- 互換性: RMIを使用してデータ・ソースにアクセスする場合、アプリケーションのサブジェクトとのセキュアでないチャネルが使用され、管理者認証は使用されません。この設定は、データ・ソースへのRMIアクセスに関するレガシー実装の動作を反映しており、クライアントで、制御されていないデータベースへのアクセスが可能になるため、セキュリティの脆弱性が潜在することになります。この設定は、強固なネットワーク・セキュリティが設置されているときにのみ使用します。「互換性」がデフォルト値です。

Oracle WebLogic Server管理コンソール・ヘルプのRMI JDBCセキュリティの有効化に関する項を参照してください。

注意:
weblogic.jdbc.remoteEnabledシステム・プロパティがtrueに設定されている場合、「RMI JDBCセキュリティ」はオーバーライドされ、既存のアプリケーションとの下位互換が保たれます。

WebLogic RMIドライバを使用するためのWebLogic Serverの設定

RMIドライバには、DataSourceオブジェクトを通してだけアクセスできます。DataSourceオブジェクトは、管理コンソールで作成します。アプリケーションでRMIドライバを使用するには、まずWebLogic Server構成にDataSourceオブジェクトを作成します。

RMIドライバを使用するサンプル・クライアント・コード

RMIドライバを使用して、WebLogic Serverデータ・ソースからデータベース接続を取得し、使用する方法を以下のサンプル・コードに示します。

必要なパッケージをインポートする

RMIドライバを使用して、データベース接続を取得/使用する前に、次のパッケージをインポートします。

javax.sql.DataSource
java.sql.*
java.util.*
javax.naming.*

データベース接続を取得する

WebLogic JDBC/RMIクライアントは、管理コンソールで定義されたDataSourceからDBMSへの接続を取得します。クライアントは、以下の2通りの方法でDataSourceオブジェクトを取得できます。

- JNDIルックアップを使用します。これが最も直接的で望ましい方法です。

- Driver.connect()メソッドでDataSource名をRMIドライバに渡します。この場合、WebLogic Serverはクライアントに代わってJNDIルックアップを実行します。

JNDIルックアップを使用して接続を取得する

JNDIを使用してWebLogic RMIドライバにアクセスするには、DataSourceオブジェクトの名前をルックアップすることで、JNDIツリーからContextオブジェクトを取得します。たとえば、管理コンソールで定義された「myDataSource」というDataSourceにアクセスするには、以下のようにします。

Context ctx = null;
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL,
"t3://hostname:port");
try {
ctx = new InitialContext(ht);
javax.sql.DataSource ds
= (javax.sql.DataSource) ctx.lookup ("myDataSource");
java.sql.Connection conn = ds.getConnection();
// You can now use the conn object to create
//  a Statement object to execute
//  SQL statements and process result sets:
Statement stmt = conn.createStatement();
stmt.execute("select * from someTable");
ResultSet rs = stmt.getResultSet();
// Do not forget to close the statement and connection objects
//  when you are finished:
}
catch (Exception e) {
// a failure occurred
log message;
}
} finally {
try {
ctx.close();
} catch (Exception e) {
log message; }
try {
if (rs != null) rs.close();
} catch (Exception e) {
log message; }
try {
if (stmt != null) stmt.close();
} catch (Exception e) {
log message; }
try {
if (conn != null) conn.close();
} catch (Exception e) {
log message; }
}

(hostnameはWebLogic Serverが稼働するマシンの名前、portはそのマシンにおいて接続リクエストをリスニングするポートの番号です)。

この例では、ハッシュ表オブジェクトを使用して、JNDIルックアップに必要なパラメータを渡しています。JNDIルックアップを実行するには他の方法もあります。詳細は、『Oracle WebLogic Server JNDIのプログラミング』を参照してください。

ルックアップの失敗を捕捉するためにJNDIルックアップがtry/catchブロックで包まれている点、コンテキストがfinallyブロックの中で閉じられている点に留意します。

WebLogic RMIドライバだけを使用してデータベース接続を取得する

DataSourceオブジェクトをルックアップしてデータベース接続を取得する代わりに、Driver.connect()メソッドを使用してWebLogic Serverにアクセスできます。この場合は、JDBC/RMIドライバによってJNDIルックアップが実行されます。WebLogic Serverにアクセスするには、WebLogic ServerのURLとDataSourceオブジェクトの名前を定義するパラメータをDriver.connect()メソッドに渡します。たとえば、管理コンソールで定義された「myDataSource」というDataSourceにアクセスするには、以下のようにします。

java.sql.Driver myDriver = (java.sql.Driver)
Class.forName("weblogic.jdbc.rmi.Driver").newInstance();
String url = "jdbc:weblogic:rmi";
java.util.Properties props = new java.util.Properties();
props.put("weblogic.server.url", "t3://hostname:port");
props.put("weblogic.jdbc.datasource", "myDataSource");
java.sql.Connection conn = myDriver.connect(url, props);

(hostnameはWebLogic Serverが稼働するマシンの名前、portはそのマシンにおいて接続リクエストをリスニングするポートの番号です)。

また、JNDIユーザー情報を設定するために使用する以下のプロパティも定義できます。

- weblogic.user - ユーザー名を指定します。

- weblogic.credential - weblogic.userのパスワードを指定します。

WebLogic RMIドライバによる行キャッシング

行キャッシングは、アプリケーションのパフォーマンスを向上させるためのWebLogic Server JDBC機能です。通常、クライアントでResultSet.next()を呼び出すと、WebLogic ServerではDBMSから単一行を取得し、これをクライアントJVMに転送します。行キャッシングが有効になっていると、ResultSet.next()を1回呼び出すだけで複数のDBMS行が取得され、これらがクライアント・メモリーにキャッシュされます。行キャッシングを行うと、データ取得のための通信の回数が減ることでパフォーマンスが向上します。

注意:
クライアントとWebLogic Serverが同じJVMにある場合、行キャッシングは実行されません。

行キャッシングは、データ・ソースの「行のプリフェッチを有効化」属性で有効にしたり無効にしたりできます。また、ResultSet.next()の呼出しごとに取得される行の数は、データ・ソース属性「プリフェッチする行サイズ」で設定します。データ・ソースの属性は、管理コンソールで設定します。行キャッシングを有効にして、データ・ソースに行のプリフェッチ・サイズの属性を設定するには、次の手順に従います。

1. まだ行っていない場合、管理コンソールのチェンジ・センターで「ロックして編集」をクリックします。

2. 「ドメイン構造」ツリーで「サービス」>「JDBC」を展開し、「データ・ソース」を選択します。

3. 「データ・ソースの概要」ページでデータ・ソース名をクリックします。

4. 「構成」>「全般」タブを選択してから、以下の作業を行います。

1. 「行のプリフェッチを有効化」チェック・ボックスを選択します。

2. 「プリフェッチする行のサイズ」に、ResultSet.next()の呼出しごとにキャッシュする行の数を入力します。

5. 「保存」をクリックします。

6. 管理コンソールのチェンジ・センターで「変更のアクティブ化」をクリックしてこれらの変更をアクティブ化します。

Oracle WebLogic Server管理コンソール・ヘルプの「JDBCデータ・ソース>構成>一般」ページを参照してください。

WebLogic RMIドライバによる行キャッシングの重要な制限事項

RMIドライバを使用して行キャッシングを実装する場合は、以下の制限事項があることに注意してください。

- 行キャッシングは、結果セット型がTYPE_FORWARD_ONLYおよびCONCUR_READ_ONLYの両方である場合にのみ実行されます。

- 結果セットのデータ型によっては、その結果セットのキャッシングが無効である場合があります。これには以下が含まれます。

- LONGVARCHAR/LONGVARBINARY

- NULL

- BLOB/CLOB

- ARRAY

- REF

- STRUCT

- JAVA_OBJECT

- 行キャッシングが有効で、その結果セットに対してアクティブな場合、一部のResultSetメソッドはサポートされません。そのほとんどは、ストリーミング・データ、スクロール可能な結果セット、または行キャッシングがサポートされていないデータ型に関係しています。これには以下が含まれます。

- getAsciiStream()

- getUnicodeStream()

- getBinaryStream()

- getCharacterStream()

- isBeforeLast()

- isAfterLast()

- isFirst()

- isLast()

- getRow()

- getObject (Map)

- getRef()

- getBlob()/getClob()

- getArray()

- getDate()

- getTime()

- getTimestamp()

グローバル・トランザクション使用時の制限事項

グローバル・トランザクション内におけるRowSetの取得は、「フェッチ順序無効」例外によって失敗することがあります。次に例を示します。

1. RMI呼出しが返ると、グローバル・トランザクションはサーバー・インスタンスによって自動的に中断されます。

2. JDBCドライバは、保留中のResultSetオブジェクトを無効化して、システム・リソースを解放します。

3. クライアントは、無効化されたResultSetからデータを読み出そうとします。

4. データがプリフェッチされていなかった場合、「フェッチ順序無効」例外がスローされます。プリフェッチされる行数はベンダーによって異なるため、特に1行または2行での作業を行っているのであれば、この問題が生じる場合と生じない場合があります。

この例外が発生した場合は、必ずRowSetをサーバー側で取得し、その後それをクライアントにシリアライズして戻すようにします。

WebLogic JTSドライバの使い方(非推奨)

JTS (Java Transaction Services)ドライバは、WebLogic Server内で実行中のアプリケーションからデータ・ソースやグローバル・トランザクションへのアクセスを提供する、サーバー側Java JDBC (Java Database Connectivity)ドライバです。データベースへの接続はデータ・ソースから行われ、アプリケーションに代わってデータベース管理システム(DBMS)に接続するためにWebLogic Server内のJDBCドライバが使用されます。アプリケーションでは、データ・ソースから取得した接続へのアクセスにJTSドライバが使用されます。

WebLogic Server ではまた、非XAのJDBCドライバを使用するデータ・ソースからの接続がグローバル・トランザクションに参加する際に、JTSドライバが内部的に使用されます(ロギング・ラスト・リソースおよび2フェーズ・コミットのエミュレート)。この動作により、非XAのリソースがXAをエミュレートし、2フェーズ・コミット・トランザクションに参加できるようになります。『Oracle WebLogic Server JDBCデータ・ソースの構成と管理』のJDBCデータ・ソース・トランザクション・オプションに関する項を参照してください。

注意:
ロギング・ラスト・リソース(LLR)、1フェーズ・コミットまたは2フェーズ・コミットのエミュレートを使用する接続に参加する場合、WebLogic Server JTSドライバではT3プロトコルのみサポートされます。

トランザクションが開始されると、同じデータ・ソースから接続を取得する実行スレッドのすべてのデータベース操作で、そのデータ・ソースの同じ接続が共有されます。これらの操作は、Enterprise JavaBean (EJB)やJava Messaging Service (JMS)のようなサービスを通じて、または標準JDBC呼出しを使用して直接SQLを送信することにより行うことができます。デフォルトでは、これらの操作はすべて同じ接続を共有し、同じトランザクションに参加します。トランザクションがコミットまたはロールバックされると、接続はプールに戻されます。

JavaクライアントはJTSドライバ自身を登録しない場合もありますが、Remote Method Invocation (RMI)を介してトランザクションに参加することができます。あるクライアントの1つのスレッド内でトランザクションを開始し、そのクライアントにリモートRMIオブジェクトを呼び出させることができます。リモート・オブジェクトによって実行されるデータベース操作は、そのクライアント上で開始されたトランザクションの一部分になります。そのリモート・オブジェクトがそれを呼び出したクライアントに戻されたら、そのトランザクションをコミットまたはロールバックできます。リモート・オブジェクトによって実行されるデータベース操作は、すべて必ず同一のデータ・ソースを使用して、同一のトランザクションの一部になる必要があります。

JTSドライバおよびアプリケーションがグローバル・トランザクションに参加するためには、アプリケーションはグローバル・トランザクション内でconn = myDriver.connect("jdbc:weblogic:jts", props);を呼び出す必要があります。トランザクションが完了する(コミットまたはロールバックされる)と、接続はデータ・ソースに返されます。別のグローバル・トランザクションで接続を使用する場合、アプリケーションは新しいグローバル・トランザクション内で再度conn = myDriver.connect("jdbc:weblogic:jts", props);を呼び出す必要があります。

JTSドライバを使用するサンプル・クライアント・コード

JTSドライバを使用するには、まず管理コンソールを使用してWebLogic Serverにデータ・ソースを作成する必要があります。

次に、サーバー側アプリケーションからJTSトランザクションを作成して使用する方法について説明します。ここでは、「myDataSource」というデータ・ソースを使用します。

1. 以下のクラスをインポートします。

import javax.transaction.UserTransaction;
import java.sql.*;
import javax.naming.*;
import java.util.*;
import weblogic.jndi.*;

2. UserTransactionクラスを使用してトランザクションを確立します。JNDIツリー上でこのクラスをルックアップできます。UserTransactionクラスは、現在の実行スレッド上のトランザクションを制御します。このクラスはトランザクション自身を表さないことに注意してください。このトランザクションの実際のコンテキストは、現在の実行スレッドに関連付けられています。

Context ctx = null;
Hashtable env = new Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");

// Parameters for the WebLogic Server.
// Substitute the correct hostname, port number
// user name, and password for your environment:
env.put(Context.PROVIDER_URL, "t3://localhost:7001");
env.put(Context.SECURITY_PRINCIPAL, "Fred");
env.put(Context.SECURITY_CREDENTIALS, "secret");

ctx = new InitialContext(env);

UserTransaction tx = (UserTransaction)
ctx.lookup("javax.transaction.UserTransaction");

3. 現在のスレッドのトランザクションを開始します。

// Start the global transaction before getting a connection
tx.begin();

4. JTSドライバをロードします。

Driver myDriver = (Driver)
Class.forName("weblogic.jdbc.jts.Driver").newInstance();

5. データ・ソースから接続を取得します。

Properties props = new Properties();
props.put("connectionPoolID", "myDataSource");

conn = myDriver.connect("jdbc:weblogic:jts", props);

6. データベース操作を実行します。これらの操作は、EJB、JMS、および標準JDBC文など、データベース接続を使用するどのサービスでも実行できます。これらの操作では、必ずJTSドライバを使用して、手順3で開始したトランザクションと同じデータ・ソースにアクセスすることによって、このトランザクションに参加するようにします。
JTSドライバを使用する追加のデータベース操作で、手順5で指定したデータ・ソースとは違うデータ・ソースを使用すると、そのトランザクションをコミットまたはロールバックしようとしたときに例外が発生します。

7. 接続オブジェクトを閉じます。接続を閉じても、それでトランザクションがコミットされるわけでも、その接続がプールに戻されるわけでもないことに注意してください。

conn.close();

8. そのトランザクションをコミットまたはロールバックすることにより、トランザクションを完了します。JTSドライバは、現在のスレッドに存在するすべての接続オブジェクトのすべてのトランザクションをコミットし、接続をプールに返します。

tx.commit();

// or:

tx.rollback();

WebLogic Poolドライバの使い方(非推奨)

WebLogicプール・ドライバを使用すると、HTTPサーブレットまたはEJBなどのサーバー側アプリケーションからデータ・ソースを利用できます。プール・ドライバの使用方法の詳細は、『Oracle WebLogic Server Webアプリケーション、サーブレットおよびJSPの開発』のデータベースのアクセスに関する項を参照してください。

6 JDBCドライバでのAPI拡張機能の使い方

この章では、サードパーティのJDBCドライバの設定方法と使用方法について、API拡張機能の使用、Oracle仮想プライベート・データベース、Oracle Thin Driverに対するバッチ処理も含めて説明します。

注意:
後続の項に記載されているweblogic.jdbc.vendor.oracle.*インタフェースは非推奨で、WebLogic Serverの今後のリリースで削除される可能性があります。

- JDBCインタフェースのAPI拡張機能の使い方

- Oracle JDBC型に対するAPI拡張機能の使用

- Oracle Thin Driverに対する非推奨のAPI拡張機能の使用

- さまざまなバージョンのWebLogic Serverクライアント/サーバー間におけるAPI拡張機能のサポート

- Oracle Thin Driverの拡張機能インタフェースとサポートされるメソッドの表

- Oracle Thin Driverでのバッチ処理の使用

- Oracle仮想プライベート・データベースを使用したプログラミング

JDBCインタフェースのAPI拡張機能の使い方

Oracleを含む一部のデータベース・ベンダーでは、DBMSを使用するデータベースのデータを操作するための独自のメソッドが追加されています。これらのメソッドは、標準のJDBCインタフェースを拡張したものです。WebLogic Serverは、ベンダーのJDBCドライバでパブリック・インタフェースとして公開されているすべての拡張機能メソッドをサポートします。

JDBCドライバで公開されている拡張機能メソッドを使用するには、アプリケーション・コードに次のような手順を組み込む必要があります。

- データ・ソースでの接続の作成に使用するJDBCドライバから、ドライバ・インタフェースをインポートします。

- データ・ソースから接続を取得します。

- 接続オブジェクトをベンダーの接続インタフェース型にキャストします。

- ベンダーのドキュメントで説明されているとおりにAPI拡張機能を使用します。

- ルックアップの失敗を捕捉するためにJNDIルックアップがtry/catchブロックで包まれている点、コンテキストがfinallyブロックの中で閉じられている点に留意します。

以降の節では、サンプル・コードで詳細を示します。特定のJDBCドライバの特定の拡張機能メソッドについては、JDBCドライバ・ベンダーのドキュメントを参照してください。

JDBCインタフェースのAPI拡張機能へのアクセス方法を示すサンプル・コード

以下のサンプル・コードでは、Oracle Thin Driverで利用できる拡張機能メソッドを使用して、JDBCのAPI拡張機能の使用方法を示します。使用するJDBCドライバで公開されているメソッドに合わせて、これらの例を修正することができます。

API拡張機能へアクセスするパッケージをインポートする

データ・ソースでの接続の作成に使用するJDBCドライバから、インタフェースをインポートします。この例ではOracle Thin Driverのインタフェースを使用します。

import java.sql.*;
import java.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import oracle.jdbc.*;
// Import driver interfaces. The driver must be the same driver
// used to create the database connection in the data source.

接続を取得する

JNDI、DataSource、およびデータ・ソース・オブジェクトを使用して、データベース接続を確立します。

// Get a valid DataSource object for a data source.
// Here we assume that getDataSource() takes
// care of those details.
javax.sql.DataSource ds = getDataSource(args);
// get a java.sql.Connection object from the DataSource
java.sql.Connection conn = ds.getConnection();

接続をベンダーの接続としてキャストする

接続を取得したら、ベンダーの接続の形にキャストできます。この例ではOracle Thin DriverのOracleConnectionインタフェースを使用します。

orConn = (oracle.jdbc.OracleConnection)conn;
// This replaces the deprecated process of casting the connection
// to a weblogic.jdbc.vendor.oracle.OracleConnection. For example:
// orConn = (weblogic.jdbc.vendor.oracle.OracleConnection)conn;

API拡張機能を使用する

次のコードでは、Oracle Thin Driverで使用できるOracleの行プリフェッチ・メソッドの使い方を示します。

例6-1 API拡張機能を使用する

// Cast to OracleConnection and retrieve the
// default row prefetch value for this connection.
int default_prefetch =
((oracle.jdbc.OracleConnection)conn).getDefaultRowPrefetch();
// This replaces the deprecated process of casting the connection
// to a weblogic.jdbc.vendor.oracle.OracleConnection. For example:
// ((weblogic.jdbc.vendor.oracle.OracleConnection)conn).
//       getDefaultRowPrefetch();
System.out.println("Default row prefetch
is " + default_prefetch);
java.sql.Statement stmt = conn.createStatement();
// Cast to OracleStatement and set the row prefetch
// value for this statement. Note that this
// prefetch value applies to the connection between
// WebLogic Server and the database.
((oracle.jdbc.OracleStatement)stmt).setRowPrefetch(20);
// This replaces the deprecated process of casting the
// statement to a weblogic.jdbc.vendor.oracle.OracleStatement.
// For example:
// ((weblogic.jdbc.vendor.oracle.OracleStatement)stmt).
//       setRowPrefetch(20);
// Perform a normal sql query and process the results...
String query = "select empno,ename from emp";
java.sql.ResultSet rs = stmt.executeQuery(query);
while(rs.next()) {
java.math.BigDecimal empno = rs.getBigDecimal(1);
String ename = rs.getString(2);
System.out.println(empno + "\t" + ename);
}
rs.close();
stmt.close();
conn.close();
conn = null;
}

Oracle JDBC型に対するAPI拡張機能の使用

OracleでのJDBCの実装時、Oracle JDBC型用にインタフェースではなく具象クラスが使用されました。具象クラスの使用にはデメリットが多く、11.2.0.3のドライバには、Oracle型に対応する新規インタフェースが用意されています。具象クラスでは、現在oracle.jdbcパッケージのパブリック・インタフェースが実装されます。プログラマは可能なかぎりjava.sqlの公開されているメソッドを使用する必要があります。Oracle拡張機能のメソッドの場合、oracle.jdbcを使用します。

また、WebLogic Serverで、具象クラスの制限を回避するために使用できる、対応するインタフェースが実装されていました。これらは現在推奨されず、対応するoracle.jdbcインタフェースで置き換える必要があります。

バージョン11.2.0.3のデータベースでは、次の型のインタフェースがあります。

古いOracle型

非推奨のWLSインタフェース

新規インタフェース

oracle.sql.ARRAY

weblogic.jdbc.vendor.oracle.OracleArray

oracle.jdbc.OracleArray

oracle.sql.STRUCT

weblogic.jdbc.vendor.oracle.OracleStruct

oracle.jdbc.OracleStruct

oracle.sql.CLOB

weblogic.jdbc.vendor.oracle.OracleThinClob

oracle.jdbc.OracleClob

oracle.sql.BLOB

weblogic.jdbc.vendor.oracle.OracleThinBlob

oracle.jdbc.OracleBlob

oracle.sql.REF

weblogic.jdbc.vendor.oracle.OracleRef

oracle.jdbc.OracleRef

新規インタフェースを使用するようコードを変更することは難しくありませんが、注意が必要です。次の例ではoracle.sql.ARRAYが使用されていますが、同様の変更は他の型にも当てはまります。推奨される変更点のリストを次に示します。

- Import: 古いインタフェース(oracle.sqlまたはweblogic.jdbc.vendor.oracle)ではなく、新規インタフェース(oracle.jdbc)を使用するようインポート文を変更します。

- 宣言: 宣言には、可能なかぎり標準Javaインタフェースを使用します。Oracle拡張機能を使用する必要がある場合、oracle.jdbc下の新規Oracleインタフェースを使用します。

- メソッド: 可能なかぎり標準Javaインタフェースを使用します。

- (Oracle型): 可能なかぎり標準Javaインタフェースのメソッドを使用します。必要に応じて、oracle.jdbc下のOracleインタフェースのメソッドを使用します。

- (定義): Oracle固有のメソッド(getARRAYなど)を使用しないようにします。かわりに、標準Javaメソッド(getArray、getObjectなど)を標準Javaインタフェースがないものに対して使用します。

- (バインド): Oracle固有のメソッド(setARRAYなど)を使用しないようにします。かわりに、標準Javaメソッド(setArray、setObjectなど)を標準Javaインタフェースがないものに対して使用します。

findとsedを使用するスクリプトでインポート文の置換を行えます。次に例を示します。

find . -name "*.java" -exec egrep ... > files.list

for f in `cat files.list`; do

cat $f |sed 's@^import oracle\.sql\.ARRAY@oracle\.jdbc.OracleArray@g' > /tmp/temp.txt

mv /tmp/temp.txt $f

done

プログラマは、oracle.jdbc.OracleConnectionにファクトリ・メソッドを使用してこのインスタンスを作成する必要があります。次に例を示します。

int[] intArray = { 5, 7, 9};

oracle.sql.ArrayDescriptor aDescriptor = new oracle.sql.ArrayDescriptor("SCOTT.TYPE1", connection);

oracle.sql.ARRAY array = new oracle.sql.ARRAY(aDescriptor, connection, intArray);

次のように変更します。

int[] intArray = { 5, 7, 9};
java.sql.Array array = connection.createOracleArray("SCOTT.TYPE1", intArray);

注意:
Oracleでは匿名配列型がサポートされないため、標準のConnection.createArrayOfメソッドはサポートされません。
次の理由から、使用できなくなったメソッドがあります。

- 標準または既存のパブリック・メソッドを使用して同じ結果を得る方法があります。

- メソッドが非推奨の型を参照します。

- メソッドに付加価値があまりありません。

これらの場合、標準のAPIを使用するようコードを変更する必要があります。

Oracle Thin Driverに対する非推奨のAPI拡張機能の使用

Oracle Thin Driverのほとんどの拡張機能では、「JDBCインタフェースのAPI拡張機能の使い方」で説明したような標準的な方法を使用できます。ただし、バージョン11.2.0.3以前は、Oracle Thin Driverで、次のクラスの拡張機能メソッドに対するパブリック・インタフェースを提供していません。

- oracle.sql.ARRAY

- oracle.sql.STRUCT

- oracle.sql.REF

- oracle.sql.BLOB

- oracle.sql.CLOB

WebLogic Serverでは、これらのクラスの拡張機能メソッドにアクセスするために、独自のインタフェースを提供しています。

- weblogic.jdbc.vendor.oracle.OracleArray

- weblogic.jdbc.vendor.oracle.OracleStruct

- weblogic.jdbc.vendor.oracle.OracleRef

- weblogic.jdbc.vendor.oracle.OracleThinBlob

- weblogic.jdbc.vendor.oracle.OracleThinClob

以降の節では、これらの拡張機能のWebLogic Serverインタフェースを使用するためのサンプル・コードを示します。サポートされるメソッドのリストについては、「Oracle Thin Driver拡張機能インタフェースとサポートされるメソッドの表」を参照してください。詳細については、Oracleのドキュメントを参照してください。

注意:
このプロセスを使用すると、「Oracle Thin Driver拡張機能インタフェースとサポートされるメソッドの表」で示す拡張機能向けのWebLogic Serverインタフェースを使用できます。ただし、前述のインタフェースは非推奨で、WebLogic Serverの今後のリリースで削除される予定です。

Oracle Thin Driver拡張機能を使用する際の特別な考慮事項

JDBCインタフェースにOracle Thin Driver拡張機能を使用する場合、次の制限があります。

- Oracle拡張機能は、サーバーと同じJVMを使用したサーバー側アプリケーションのみで、ARRAY、REF、およびSTRUCTの各オブジェクトに適用できます。リモート・クライアント・アプリケーションのARRAY、REFおよびSTRUCTにOracle拡張機能は使用できません。

- 標準以外のOracle記述子オブジェクトを使用して、アプリケーション内でARRAYおよびSTRUCTを作成できます。

- Oracleオブジェクト型へのREFを含む表に対する問合せを実行できます。REFはJDBCによってJava oracle.sql.REFオブジェクトとして実体化されます。JDBCでは、ゼロからの新規REFの作成はサポートしていません。データベースに移動して新規REFをSQLに挿入し、REFを選択してクライアントに返します。

- クライアントとサーバーで異なるバージョンのWebLogic Serverを使用する場合は、相互運用性の制限があります。「さまざまなバージョンのWebLogic Serverクライアント/サーバー間におけるAPI拡張機能のサポート」を参照してください。

注意:
JDBC 4.0 APIでは、次のjava.sql.Connectionは記述子なしにアプリケーション内でSTRUCTおよびARRAYオブジェクトを作成するために使用できます。

- java.sql.Connection.createStruct(): Connection.createStruct()を使用してSQL構造体を作成するときには、すべてのデータ型(java.sql.Clob、java.sql.Blob、java.sql.Struct、java.sql.Ref、java.sql.Array、java.sql.NClob、およびjava.sql.SQLXML)のラップを解除する必要があります。構造体を作成したら、構造体をアプリケーションに返す前に構造体を再度ラップする方法はありません。アプリケーションに返される構造体は、ラップ解除されたデータ型の値を持ちます。

- java.sql.Connection.createArrayOf(): SQL仕様では匿名の配列型が必要になります。配列を使用する前の名前を持つ配列型をデータベース内に作成します。クライアント側からは配列を作成できません。

JDBCインタフェースのOracle Thin Driver拡張機能にアクセスするサンプル・コード

以下のサンプル・コードでは、11.2.0.3より前のパブリック・インタフェースとして利用できないOracle拡張機能に対するWebLogic Serverインタフェースにアクセスする方法を示します。次のようなインタフェースがあります。

- ARRAY - 「ARRAYによるプログラミング」を参照してください。

- STRUCT - 「STRUCTによるプログラミング」を参照してください。

- REF - 「REFによるプログラミング」を参照してください。

- BLOBおよびCLOB - 「BLOBとCLOBを使用したプログラミング」を参照してください。

WebLogic Serverと共にサーバー・サンプルをインストールするオプションを選択した場合は、JDBCサンプルの詳細なサンプル・コードを参照してください。JDBCサンプルは通常、WL_HOME\samples\server\src\examples\jdbcにあります。WL_HOMEはWebLogic Serverをインストールしたフォルダです。

ARRAYによるプログラミング

WebLogic Serverのサーバー側アプリケーションでは、結果セット、またはJava配列として呼出し可能文を使用することにより、Oracle Collection (SQL ARRAY)を実体化できます。

WebLogic ServerアプリケーションでARRAYを使用するには、次の手順に従います。

1. 必要なクラスをインポートします。

2. 接続を取得して、接続のための文を作成します。

3. 結果セット、または呼出し可能文を使用してARRAYを取得します。

4. ARRAYをjava.sql.Arrayまたはweblogic.jdbc.vendor.oracle.OracleArrayのいずれかとして使用します。

5. 標準Javaメソッド(java.sql.Arrayとして使用)、またはOracle拡張機能メソッド(weblogic.jdbc.vendor.oracle.OracleArrayにキャスト)を使用して、データを操作します。

以下の節では、これらのアクションの詳細について説明します。

注意:
ARRAYはサーバー側アプリケーションでのみ使用できます。リモート・クライアント・アプリケーションではARRAYは使用できません。

WebLogic Oracle拡張機能へアクセスするパッケージをインポートする

この例で使用するWebLogicインタフェースをインポートします。OracleArrayインタフェースは、oracle.sql.ARRAYに相当し、WebLogic Serverでサポートされるメソッドを使用する場合、WebLogicインタフェースと同様に使用できます。

import java.sql.*;
import java.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import weblogic.jdbc.vendor.oracle.*;

接続を確立する

JNDIとDataSourceオブジェクトを使用して、データベース接続を確立します。

// Get a valid DataSource object.
// Here we assume that getDataSource() takes
// care of those details.
javax.sql.DataSource ds = getDataSource(args);
// get a java.sql.Connection object from the DataSource
java.sql.Connection conn = ds.getConnection();

ARRAYを取得する

呼出し可能文、または結果セットにgetArray()メソッドを使用して、Java配列を取得できます。この配列をjava.sql.arrayとして使用することで標準java.sql.arrayメソッドを利用できます。またweblogic.jdbc.vendor.oracle.OracleArrayにキャストすることで、配列にOracle拡張機能メソッドを利用することもできます。

以下の例では、ARRAYを含む結果セットからjava.sql.arrayを取得する方法を示します。この例では、問合せにより、オブジェクト列(学生の成績を示すARRAY)を含む結果セットが返されます。

try {
conn = getConnection(url);
stmt = conn.createStatement();
String sql = "select * from students";
//Get the result set
rs = stmt.executeQuery(sql);
while(rs.next()) {
BigDecimal id = rs.getBigDecimal("student_id");
String name   = rs.getString("name");
log("ArraysDAO.getStudents() -- Id = "+id.toString()+", Student = "+name);
//Get the array from the result set
Array scoreArray  = rs.getArray("test_scores");
String[] scores = (String[])scoreArray.getArray();
for (int i = 0; i < scores.length; i++) {
log("   Test"+(i+1)+" = "+scores[i]);
}
}

データベースでARRAYを更新する

データベースにおけるARRAYを更新するには、次の手順に従います。

1. 更新する配列がデータベースにない場合、PL/SQLを使用してデータベースに配列を作成します。

2. 結果セット、または呼出し可能文を使用してARRAYを取得します。

3. Javaアプリケーション内の配列をjava.sql.Arrayまたはweblogic.jdbc.vendor.oracle.OracleArrayとして扱います。

4. プリペアド文または呼出し可能文にsetArray()メソッドを使用して、データベース内の配列を更新します。次に例を示します。

String sqlUpdate = "UPDATE SCOTT." + tableName + " SET col1 = ?";
conn  = ds.getConnection();
pstmt = conn.prepareStatement(sqlUpdate);
pstmt.setArray(1, array);
pstmt.executeUpdate();

Oracle Array拡張機能メソッドを使用する

ARRAYに対してOracle Thin Driver拡張機能メソッドを利用するには、まずこの配列をweblogic.jdbc.vendor.oracle.OracleArrayにキャストします。キャストが済むとARRAYに対してOracle Thin Driver拡張メソッドを呼び出せます。次に例を示します。

oracle.sql.Datum[] oracleArray = null;
oracleArray =       ((weblogic.jdbc.vendor.oracle.OracleArray)scoreArray).getOracleArray();
String sqltype = null
sqltype = oracleArray.getSQLTypeName()

STRUCTによるプログラミング

WebLogic Serverアプリケーションでは、Oracleデータベースからオブジェクトにアクセスしたり、オブジェクトを操作したりできます。Oracleデータベースからオブジェクトを検索したら、カスタムJavaオブジェクト、またはSTRUCT (java.sql.structあるいは weblogic.jdbc.vendor.oracle.OracleStruct)のいずれかとして、オブジェクトをキャストできます。STRUCTは、アプリケーション中のカスタム・クラスを置き換える構造化データを表す型制限の緩いデータ型です。JDBC APIにおけるSTRUCTインタフェースには、STRUCT中の属性値を操作するためのさまざまなメソッドが組み込まれています。Oracleでは、いくつかの追加メソッドを使用して、STRUCTインタフェースを拡張しています。WebLogic Serverでは、すべての標準メソッドと大部分のOracle拡張機能が実装されています。

注意:
STRUCTを使用する場合、次の制限があります。

- STRUCTは、Oracle専用としてサポートされるデータ型。アプリケーション中でSTRUCTを使用するには、Oracle Thin Driverを使用して(通常はデータ・ソースを介して)データベースとやり取りします。

- STRUCTはサーバー側アプリケーションでのみ使用できます。クライアント・アプリケーションではSTRUCTは使用できません。

WebLogic ServerアプリケーションでSTRUCTを使用するには、次の手順に従います。

1. 必要なクラスをインポートします。(「WebLogic Oracle拡張機能へアクセスするパッケージをインポートする」を参照)。

2. 接続を取得します(「接続を確立する」を参照)。

3. getObjectを使用してSTRUCTを取得します。

4. STRUCTをSTRUCT (標準のメソッドを使用する場合はjava.sql.Struct、標準のメソッドとOracle拡張機能メソッドを使用する場合はweblogic.jdbc.vendor.oracle.OracleStruct)にキャストします。

5. 標準メソッド、またはOracle Thin Driver拡張機能メソッドを使用して、データを操作します。

以下の節では、手順3 - 5について詳しく説明します。

STRUCTを取得する

データベース・オブジェクトをSTRUCTとして取得するには、まず問合せを使用して結果セットを作成し、次にgetObjectメソッドを使用して、結果セットからSTRUCTを取得します。その後でSTRUCTをjava.sql.Structにキャストすることにより、標準Javaメソッドを使用できるようになります。次に例を示します。

conn = ds.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from people");
struct = (java.sql.Struct)(rs.getObject(2));
Object[] attrs = ((java.sql.Struct)struct).getAttributes();

WebLogic Serverでは、STRUCTに対応するすべてのJDBC APIメソッドがサポートされます。

- getAttributes()

- getAttributes(java.util.Dictionary map)

- getSQLTypeName()

したがって、STRUCTをweblogic.jdbc.vendor.oracle.OracleStructにキャストすると、標準メソッドと拡張機能メソッドの両方を使用できるようになります。

WebLogic OracleStruct拡張機能メソッドを使用する

STRUCTにOracle Thin Driver拡張機能メソッドを使用する場合、java.sql.Struct (または元のgetObjectの結果)をweblogic.jdbc.vendor.oracle.OracleStructにキャストする必要があります。次に例を示します。

java.sql.Struct struct =
(weblogic.jdbc.vendor.oracle.OracleStruct)(rs.getObject(2));

WebLogic Serverでは次のOracle拡張機能がサポートされます。

- getDescriptor()

- getOracleAttributes()

- getAutoBuffering()

- setAutoBuffering(boolean)

STRUCT属性を取得する

STRUCTの個々の属性値を取得するには、getAttributes()およびgetAttributes(java.util.Dictionary map)の標準JDBC APIメソッド、またはOracle拡張機能メソッドgetOracleAttributes()を使用できます。

標準メソッドを使用するには、まず結果セットを作成し、この結果セットからSTRUCTを取得した後でgetAttributes()メソッドを使用します。このメソッドにより、順序の付いた属性の配列が返されます。アプリケーションのオブジェクト(Java言語タイプなど)にSTRUCT (データベースのオブジェクト)の属性を割り当てることができます。この後、属性を個別に操作できるようになります。次に例を示します。

conn = ds.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from people");
//The third column uses an object data type.
//Use getObject() to assign the object to an array of values.
struct = (java.sql.Struct)(rs.getObject(2));
Object[] attrs = ((java.sql.Struct)struct).getAttributes();
String address = attrs[1];

上の例で、people表の第3列ではオブジェクト・データ型を使用しています。この例では、値の配列を含むJavaオブジェクトにgetObjectメソッドの結果を割り当て、必要に応じて配列中の個別の値を使用する方法を示しています。

また、getAttributes(java.util.Dictionary map)メソッドを使用しても、STRUCTから属性を取得できます。このメソッドを使用する場合は、Java言語データ型にOracleオブジェクトのデータ型をマップするためのハッシュ表を用意する必要があります。次に例を示します。

java.util.Hashtable map = new java.util.Hashtable();
map.put("NUMBER", Class.forName("java.lang.Integer"));
map.put("VARCHAR", Class.forName("java.lang.String"));
Object[] attrs = ((java.sql.Struct)struct).getAttributes(map);
String address = attrs[1];

また、Oracle拡張機能メソッドgetOracleAttributes()を使用して、STRUCTの属性を取得することもできます。まず、STRUCTをweblogic.jdbc.vendor.oracle.OracleStructにキャストする必要があります。このメソッドにより、oracle.sql.Datumオブジェクトのデータ配列が返されます。次に例を示します。

oracle.sql.Datum[] attrs =
((weblogic.jdbc.vendor.oracle.OracleStruct)struct).getOracleAttributes();
oracle.sql.STRUCT address = (oracle.sql.STRUCT) attrs[1];
Object address_attrs[] = address.getAttributes();

上の例では、STRUCTがネスト構造になっています。つまり、ここで返されるデータ配列には、別のSTRUCTが入れ子の構造で組み込まれています。

STRUCTによってデータベース・オブジェクトを更新する

STRUCTを使用してデータベースのオブジェクトを更新するには、プリペアド文にあるsetObjectメソッドを使用します。次に例を示します。

conn  = ds.getConnection();
stmt = conn.createStatement();
ps = conn.prepareStatement ("UPDATE SCHEMA.people SET EMPLNAME = ?,
EMPID = ? where EMPID = 101");
ps.setString (1, "Smith");
ps.setObject (2, struct);
ps.executeUpdate();

WebLogic Serverでは、setObjectメソッドの3つのバージョンがすべてサポートされます。

データベース・オブジェクトを作成する

STRUCTは通常Javaアプリケーション中で、データベース・オブジェクトにマップするカスタムJavaクラスの代わりに、データベース・オブジェクトを実体化する場合に使用します。WebLogic Serverアプリケーションでは、データベースに転送するSTRUCTは作成できません。一方で、アプリケーションから検索や操作が実行できるようなデータベース・オブジェクトを作成する文は使用できます。次に例を示します。

conn = ds.getConnection();
stmt = conn.createStatement();
cmd = "create type ob as object (ob1 int, ob2 int)"
stmt.execute(cmd);
cmd = "create table t1 of type ob";
stmt.execute(cmd);
cmd = "insert into t1 values (5, 5)"
stmt.execute(cmd);

注意:
アプリケーションでSTRUCTは作成できません。データベースから既存のオブジェクトを検索して、これをSTRUCTにキャストすることはできます。アプリケーションでSTRUCTオブジェクトを作成するには、標準外のOracle STRUCT記述子オブジェクトを使用します。ただし、WebLogic Serverではサポートされません。

STRUCT属性を自動バッファリングする

STRUCTを使用するWebLogic Serverアプリケーションのパフォーマンスを向上させるために、setAutoBuffering(boolean)メソッドで自動バッファリング機能を切り換えることができます。自動バッファリングをtrueに設定すると、weblogic.jdbc.vendor.oracle.OracleStructオブジェクトに、STRUCTオブジェクトにあるすべての属性のローカル・コピーが変換済みのフォーム(すなわちSQLからJava言語オブジェクトに実体化した形式)で保持されます。アプリケーションが、STRUCTに再びアクセスした時点で、データを再度変換する必要はありません。

注意:
変換した属性をバッファリングすると、アプリケーションで使用するメモリー量が過度に増大することがあります。自動バッファリングの有効/無効を切り換えるときは、可能メモリー使用量についても考慮してください。

以下の例は、自動バッファリングをアクティブにする方法を示します。

((weblogic.jdbc.vendor.oracle.OracleStruct)struct).setAutoBuffering(true);

また、getAutoBuffering()メソッドを使用して、自動バッファリング・モードを判断することもできます。

REFによるプログラミング

REFは、行オブジェクトに対する論理ポインタです。REFを検索すると、実際には別の表にある値を指すポインタが返されます。REFのターゲットは、オブジェクト表の行でなければなりません。REFを使用して、これが参照するオブジェクトを検証したり、更新したりできます。またREFを変更することにより、同じオブジェクト・タイプの別のオブジェクトを指示したり、null値を割り当てたりすることができます。

注意:
REFを使用する場合、次の制限があります。

- REFは、Oracleデータベースでのみ使用できます。アプリケーション中でREFを使用するには、Oracle Thin Driverを使用して(通常はデータ・ソースを介して)データベースとやり取りします。

- REFはサーバー側アプリケーションでのみ使用できます。

WebLogic ServerアプリケーションでREFを使用するには、次の手順に従います。

1. 必要なクラスをインポートします。(「WebLogic Oracle拡張機能へアクセスするパッケージをインポートする」を参照)。

2. データベース接続を取得します(「接続を確立する」を参照)。

3. 結果セット、または呼出し可能文を使用してREFを取得します。

4. 結果をSTRUCT、またはJavaオブジェクトにキャストします。これにより、STRUCTメソッド、またはJavaオブジェクトのメソッドを使用して、データを操作できるようになります。

また、データベースでREF作成したり、更新したりできます。

手順3と4について以下の節で詳しく説明します。

REFを取得する

アプリケーションでREFを取得するには、まず問合せを使用して結果セットを作成し、次にgetRefメソッドを使用して、結果セットからREFを取得します。続いてREFをjava.sql.Refにキャストすることにより、組込みJavaメソッドを使用できます。次に例を示します。

conn = ds.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT ref (s) FROM t1 s where s.ob1=5");
rs.next();
//Cast as a java.sql.Ref and get REF
ref = (java.sql.Ref) rs.getRef(1);

なお、上の例のWHERE句では、ドット表記法を使用して、参照するオブジェクトの属性を指定しています。

REFをjava.sql.Refにキャストした後は、Java APIメソッドgetBaseTypeNameを使用できます(これはREFに対応した唯一のJDBC 2.0標準メソッドです)。

REFを取得すると、実際には別のオブジェクト表にある値を指すポインタが返されます。REF値の取得や操作を行うには、Oracle拡張機能を使用します。この拡張機能は、sql.java.Refをweblogic.jdbc.vendor.oracle.OracleRefにキャストする場合に限り使用できます。

WebLogic OracleRef拡張機能メソッドを使用する

REFにOracle Thin Driver拡張機能メソッドを使用するには、REFをOracle REFにキャストします。次に例を示します。

oracle.sql.StructDescriptor desc =       ((weblogic.jdbc.vendor.oracle.OracleRef)ref).getDescriptor();

WebLogic Serverでは次のOracle Thin Driver拡張機能がサポートされます。

- getDescriptor()

- getSTRUCT()

- getValue()

- getValue(dictionary)

- setValue(object)

値を取得する

Oracle Thin Driverでは、2つのバージョンのgetValue()メソッドが提供されています。パラメータを取らないメソッドと、戻り値の型をマップするハッシュ表を必要とするメソッドの2種類です。いずれかのgetValue()メソッドを使用してREFの属性値を取得すると、STRUCTまたはJavaオブジェクトのいずれかの形式で結果が返されます。

パラメータを取らないgetValue()メソッドを使用する方法を以下の例で示します。この例では、REFがoracle.sql.STRUCT型にキャストされます。getAttributes()メソッドの説明で示したとおり、STRUCTメソッド群を使用して値を操作できます。

oracle.sql.STRUCT student1 =
(oracle.sql.STRUCT)((weblogic.jdbc.vendor.oracle.OracleRef)ref).getValue ();
Object attributes[] = student1.getAttributes();

また、getValue(dictionary)メソッドを使用して、REFの値を取得できます。またREFの属性ごとにデータ型をJava言語データ型にマップするためのハッシュ表を用意する必要があります。次に例を示します。

java.util.Hashtable map = new java.util.Hashtable();
map.put("VARCHAR", Class.forName("java.lang.String"));
map.put("NUMBER", Class.forName("java.lang.Integer"));
oracle.sql.STRUCT result = (oracle.sql.STRUCT)
((weblogic.jdbc.vendor.oracle.OracleRef)ref).getValue (map);

REF値を更新する

REFの更新では、次のような操作が行えます。

- setValue(object)メソッドを使用して、基底の表の値を変更する

- プリペアド文または呼出し可能文を使用してREFが指示する位置を変更する

- REFの値をnullに設定する

setValue(object)メソッドを使用してREF値を更新する場合は、REFの新しい値を持つオブジェクトを作成してから、そのオブジェクトをsetValueメソッドのパラメータとして渡します。次に例を示します。

STUDENT s1 = new STUDENT();
s1.setName("Terry Green");
s1.setAge(20);
((weblogic.jdbc.vendor.oracle.OracleRef)ref).setValue(s1);

REFの値をsetValue(object)メソッドで更新すると、実際にはREFが示す表の値が更新されます。

プリペアド文を使用してREFが指示する位置を更新するには、次の基本手順に従います。

1. 新しい位置を指示するREFを取得します。このREFを使用して、別のREFの値を置き換えます。

2. SQLコマンドの文字列を作成して、既存のREFの位置を、別のREFの値で置き換えます。

3. プリペアド文を作成、および実行します。

次に例を示します。

try {
conn = ds.getConnection();
stmt = conn.createStatement();
//Get the REF.
rs = stmt.executeQuery("SELECT ref (s) FROM t1 s where s.ob1=5");
rs.next();
ref = (java.sql.Ref) rs.getRef(1); //cast the REF as a java.sql.Ref
}
//Create and execute the prepared statement.
String sqlUpdate = "update t3 s2 set col = ? where s2.col.ob1=20";
pstmt = conn.prepareStatement(sqlUpdate);
pstmt.setRef(1, ref);
pstmt.executeUpdate();

呼出し可能文を使用して、REFが指示する位置を更新する場合は、まずストアド・プロシージャを作成し、いずれかのINパラメータを設定して、OUTパラメータを登録した後、文を実行します。ストアド・プロシージャでは、実際の位置を指示するREF値が更新されます。次に例を示します。

conn = ds.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT ref (s) FROM t1 s where s.ob1=5");
rs.next();
ref1 = (java.sql.Ref) rs.getRef(1);
// Prepare the stored procedure
sql = "{call SP1 (?, ?)}";
cstmt = conn.prepareCall(sql);
// Set IN and register OUT params
cstmt.setRef(1, ref1);
cstmt.registerOutParameter(2, getRefType(), "USER.OB");
// Execute
cstmt.execute();

データベースでREFを作成する

JDBCアプリケーションにREFオブジェクトは作成できません。単に、データベースから既存のREFオブジェクトが検索されるだけです。ただし、文またはプリペアド文を使用して、データベースにREFを作成できます。次に例を示します。

conn = ds.getConnection();
stmt = conn.createStatement();
cmd = "create type ob as object (ob1 int, ob2 int)"
stmt.execute(cmd);
cmd = "create table t1 of type ob";
stmt.execute(cmd);
cmd = "insert into t1 values (5, 5)"
stmt.execute(cmd);
cmd = "create table t2 (col ref ob)";
stmt.execute(cmd);
cmd = "insert into t2 select ref(p) from t1 where p.ob1=5";
stmt.execute(cmd);

上の例では、オブジェクト型(ob)、このオブジェクト型の表(t1)、obオブジェクトのインスタンスを示すREF列のある表(t2)が作成され、REFがREF列に挿入されます。REFは、t1の行を指します(最初の列の値は5)。

BLOBとCLOBを使用したプログラミング

この節では、OracleBlobインタフェースへのアクセス方法を示すサンプル・コードについて説明します。WebLogic Serverでサポートされるメソッドを使用している場合、この例で示す構文は、OracleBlobインタフェースで使用できます。「Oracle Thin Driverの拡張機能インタフェースとサポートされるメソッドの表」を参照してください。

注意:
BLOBおよびCLOB (「LOB」と呼ばれる)を使用する場合、トランザクションの境界を考慮する必要があります。たとえば、すべての読取り/書込みをトランザクション内の特定のLOBに転送します。詳細については、Oracle Webサイト(http://www.oracle.com)にあるOracleのドキュメントの「LOB Locators and Transaction Boundaries」を参照してください。

DBMSからBLOBロケータを選択する問合せを実行する

BLOBロケータまたはハンドルは、Oracle Thin Driver Blobへの参照です。

String selectBlob = "select blobCol from myTable where blobKey = 666"

WebLogic Server java.sqlオブジェクトを宣言する

次のコードでは、Connectionがすでに確立されていることを前提としています。

ResultSet rs = null;
Statement myStatement = null;
java.sql.Blob myRegularBlob = null;
java.io.OutputStream os = null;

SQL例外ブロックを開始する

このtry/catchブロックでは、BLOBロケータを取得して、Oracle Blob拡張機能にアクセスします。

try {
// get our BLOB locator..
myStatement = myConnect.createStatement();
rs = myStatement.executeQuery(selectBlob);
while (rs.next()) {
myRegularBlob = rs.getBlob("blobCol");
}
// Access the underlying Oracle extension functionality for
// writing. Cast to the OracleThinBlob interface to access
// the Oracle method.
os = ((OracleThinBlob)myRegularBlob).getBinaryOutputStream();
...
} catch (SQLException sqe) {
System.out.println("ERROR(general SQE): " +
sqe.getMessage());
}

Oracle.ThinBlobインタフェースにキャストしたら、Oracleがサポートするメソッドにアクセスできます。

プリペアド文を使用したCLOB値の更新

プリペアド文を使用してCLOBを更新し、新しい値が以前の値より短い場合、CLOBには更新中に明示的に置換されなかった文字が保持されます。たとえば、CLOBの現在の値がabcdefghijの場合に、プリペアド文を使用してzxywでCLOBを更新すると、CLOBの値はzxywefghijになります。プリペアド文で更新された値を修正するには、dbms_lob.trimプロシージャを使用して、更新後に残った余分な文字を削除します。dbms_lob.trimプロシージャの詳細については、Oracleのドキュメントを参照してください。

さまざまなバージョンのWebLogic Serverクライアント/サーバー間におけるAPI拡張機能のサポート

一般に、WebLogic ServerはAPI拡張機能のサーバー側コードでの使用をサポートしています。API拡張機能をクライアント側コードで使用するには、オブジェクト型またはデータ型がシリアライズ可能でなければなりません。これに対する例外として、以下のオブジェクト型があります。

- CLOB

- BLOB

- InputStream

- OutputStream

これらのオブジェクト型についてはWebLogic Serverでデシリアライゼーションが行われるので、クライアント側コードで使用できます。

WebLogic ServerでのベンダーのJDBC拡張機能のサポート方法はWebLogic Server 8.1で変更されました。その影響で、様々なバージョンのクライアント/サーバー間の相互運用性が変更されています。WebLogic Server 8.1以降のクライアントがWebLogic Server 7.0以前のサーバーと対話する場合、Oracle拡張機能はサポートされません。クライアント・アプリケーションでJDBCオブジェクトをOracle拡張機能インタフェースにキャストしようとすると、ClassCastExceptionを受け取ります。ただし、WebLogic Server 7.0以前のクライアントがWebLogic Server 8.1以降のサーバーと対話する場合、Oracle拡張機能はサポートされます。

注意:
weblogic.jdbc.vendor.oracle.*インタフェースは非推奨で、WebLogic Serverの今後のリリースで削除される可能性があります。標準のJDBCインタフェースは、クライアントまたはサーバーのバージョンに関係なくサポートされます。

Oracle Thin Driverの拡張機能インタフェースとサポートされるメソッドの表

以前のリリースのWebLogic Serverでは、以下の表に示すJDBC拡張機能のみがサポートされていました。現在のリリースのWebLogic Serverは、ベンダーのJDBCドライバでパブリック・インタフェースとして公開されているほとんどの拡張機能メソッドをサポートします。API拡張機能の使用手順については、「JDBCインタフェースのAPI拡張機能の使い方」を参照してください。API拡張機能をサポートするための新しい内部メカニズムは以前の実装に依存していないため、一部のインタフェースは不要になって非推奨となりました。これらのインタフェースはWebLogic Serverの今後のリリースで削除される予定です。表6-1を参照してください。表に示された代わりのインタフェースを使用することをお薦めします。

表6-1 Oracle JDBC拡張機能の非推奨になったインタフェース

非推奨のインタフェース

かわりに使用するOracleのインタフェース

weblogic.jdbc.vendor.oracle.
OracleConnection

oracle.jdbc.OracleConnection

weblogic.jdbc.vendor.oracle.
OracleStatement

oracle.jdbc.OracleStatement

weblogic.jdbc.vendor.oracle.
OracleCallableStatement

oracle.jdbc.OracleCallableStatement

weblogic.jdbc.vendor.oracle.
OraclePreparedStatement

oracle.jdbc.OraclePreparedStatement

weblogic.jdbc.vendor.oracle.
OracleResultSet

oracle.jdbc.OracleResultSet

weblogic.jdbc.vendor.oracle.OracleArray

oracle.jdbc.OracleArray

weblogic.jdbc.vendor.oracle.OracleStruct

oracle.jdbc.OracleStruct

weblogic.jdbc.vendor.oracle.OracleRef

oracle.jdbc.OracleRef

weblogic.jdbc.vendor.oracle.OracleThinClob

oracle.jdbc.OracleBlob

weblogic.jdbc.vendor.oracle.OracleThinBlob

oracle.jdbc.OracleClob

Oracleインタフェースを以下の表に示します。また、標準JDBC (java.sql.*)インタフェースを拡張するためにOracle Thin Driver (またはこれらのメソッドをサポートする他のドライバ)で使用するメソッドのうち、サポートされているものについても示します。

表6-2 OracleConnectionインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleConnection

拡張

java.sql.Connectionの拡張

(このインタフェースは非推奨。)

void clearClientIdentifier(String s)
throws java.sql.SQLException;

boolean getAutoClose()
throws java.sql.SQLException;

String getDatabaseProductVersion()
throws java.sql.SQLException;

String getProtocolType() throws
java.sql.SQLException;

String getURL() throws java.sql.SQLException;

String getUserName()
throws java.sql.SQLException;

boolean getBigEndian()
throws java.sql.SQLException;

boolean getDefaultAutoRefetch() throws
java.sql.SQLException;

boolean getIncludeSynonyms()
throws java.sql.SQLException;

boolean getRemarksReporting()
throws java.sql.SQLException;

boolean getReportRemarks()
throws java.sql.SQLException;

weblogic.jdbc.vendor.oracle.OracleConnection

拡張

java.sql.Connectionの拡張

(続き)

(このインタフェースは非推奨。)

boolean getRestrictGetTables()
throws java.sql.SQLException;

boolean getUsingXAFlag()
throws java.sql.SQLException;

boolean getXAErrorFlag()
throws java.sql.SQLException;

boolean isCompatibleTo816()
throws java.sql.SQLException;
(Deprecated)

byte[] getFDO(boolean b)
throws java.sql.SQLException;

int getDefaultExecuteBatch() throws
java.sql.SQLException;

int getDefaultRowPrefetch()
throws java.sql.SQLException;

int getStmtCacheSize()
throws java.sql.SQLException;

java.util.Properties getDBAccessProperties()
throws java.sql.SQLException;

short getDbCsId() throws java.sql.SQLException;
short getJdbcCsId() throws java.sql.SQLException;
short getStructAttrCsId()
throws java.sql.SQLException;
short getVersionNumber()
throws java.sql.SQLException;

void archive(int i, int j, String s)
throws java.sql.SQLException;

weblogic.jdbc.vendor.oracle.OracleConnection

拡張

java.sql.Connectionの拡張

(続き)

(このインタフェースは非推奨。)

void close_statements()
throws java.sql.SQLException;

void initUserName() throws java.sql.SQLException;

void logicalClose() throws java.sql.SQLException;

void needLine() throws java.sql.SQLException;

void printState() throws java.sql.SQLException;

void registerSQLType(String s, String t)
throws java.sql.SQLException;

void releaseLine() throws java.sql.SQLException;

void removeAllDescriptor()
throws java.sql.SQLException;

void removeDescriptor(String s)
throws java.sql.SQLException;

void setAutoClose(boolean on) throws
java.sql.SQLException;

void setClientIdentifier(String s)
throws java.sql.SQLException;

void clearClientIdentifier(String s) throws java.sql.SQLException;

void setDefaultAutoRefetch(boolean b)
throws java.sql.SQLException;

void setDefaultExecuteBatch(int i)
throws java.sql.SQLException;

void setDefaultRowPrefetch(int i)
throws java.sql.SQLException;

void setFDO(byte[] b)
throws java.sql.SQLException;

void setIncludeSynonyms(boolean b)
throws java.sql.SQLException;

weblogic.jdbc.vendor.oracle.OracleConnection

拡張

java.sql.Connectionの拡張

(続き)

(このインタフェースは非推奨。)

void setPhysicalStatus(boolean b)
throws java.sql.SQLException;

void setRemarksReporting(boolean b)
throws java.sql.SQLException;

void setRestrictGetTables(boolean b)
throws java.sql.SQLException;

void setStmtCacheSize(int i)
throws java.sql.SQLException;

void setStmtCacheSize(int i, boolean b)
throws java.sql.SQLException;

void setUsingXAFlag(boolean b)
throws java.sql.SQLException;

void setXAErrorFlag(boolean b)
throws java.sql.SQLException;

void shutdown(int i)
throws java.sql.SQLException;

void startup(String s, int i)
throws java.sql.SQLException;

表6-3 OracleStatementインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleStatement

拡張

java.sql.Statement

(このインタフェースは非推奨。)

String getOriginalSql()
throws java.sql.SQLException;
(Removed in Oracle 11g.)

String getRevisedSql()
throws java.sql.SQLException;
(Deprecated in Oracle 8.1.7, removed in Oracle 9i.)

boolean getAutoRefetch()
throws java.sql.SQLException;

boolean is_value_null(boolean b, int i)
throws java.sql.SQLException;

byte getSqlKind()
throws java.sql.SQLException;

int creationState()
throws java.sql.SQLException;

int getAutoRollback()
throws java.sql.SQLException;
(Deprecated)

int getRowPrefetch()
throws java.sql.SQLException;

int getWaitOption()
throws java.sql.SQLException;
(Deprecated)

int sendBatch()
throws java.sql.SQLException;

weblogic.jdbc.vendor.oracle.OracleStatement

拡張

java.sql.Statement

(このインタフェースは非推奨。)

void clearDefines()
throws java.sql.SQLException;

void defineColumnType(int i, int j)
throws java.sql.SQLException;

void defineColumnType(int i, int j, String s)
throws java.sql.SQLException;

void defineColumnType(int i, int j, int k)
throws java.sql.SQLException;

void describe()
throws java.sql.SQLException;

void setAutoRefetch(boolean b)
throws java.sql.SQLException;

void setAutoRollback(int i)
throws java.sql.SQLException;
(Deprecated)

void setRowPrefetch(int i)
throws java.sql.SQLException;

void setWaitOption(int i)
throws java.sql.SQLException;
(Deprecated)

表6-4 OracleResultSetインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleResultSet

拡張

java.sql.ResultSetの拡張

(このインタフェースは非推奨。)

boolean getAutoRefetch()
throws java.sql.SQLException;

int getFirstUserColumnIndex()
throws java.sql.SQLException;

void closeStatementOnClose()
throws java.sql.SQLException;

void setAutoRefetch(boolean b)
throws java.sql.SQLException;

java.sql.ResultSet getCursor(int n)
throws java.sql.SQLException;

java.sql.ResultSet getCURSOR(String s)
throws java.sql.SQLException;

表6-5 OracleCallableStatementインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleCallableStatement

拡張

java.sql.CallableStatementの拡張

(このインタフェースは非推奨。)

void clearParameters()
throws java.sql.SQLException;

void registerIndexTableOutParameter(int i,
int j, int k, int l)
throws java.sql.SQLException;

void registerOutParameter
(int i, int j, int k, int l)
throws java.sql.SQLException;

java.sql.ResultSet getCursor(int i)
throws java.sql.SQLException;

java.io.InputStream getAsciiStream(int i)
throws java.sql.SQLException;

java.io.InputStream getBinaryStream(int i)
throws java.sql.SQLException;

java.io.InputStream getUnicodeStream(int i)
throws java.sql.SQLException;

表6-6 OraclePreparedStatementインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OraclePreparedStatement

拡張

OracleStatementおよびjava.sql.PreparedStatementの拡張

(このインタフェースは非推奨。)

int getExecuteBatch()
throws java.sql.SQLException;

void defineParameterType(int i, int j, int k)
throws java.sql.SQLException;

void setDisableStmtCaching(boolean b)
throws java.sql.SQLException;

void setExecuteBatch(int i)
throws java.sql.SQLException;

void setFixedCHAR(int i, String s)
throws java.sql.SQLException;

void setInternalBytes(int i, byte[] b, int j)
throws java.sql.SQLException;

表6-7 OracleArrayインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleArray

拡張

java.sql.Arrayの拡張

(このインタフェースは非推奨。

public ArrayDescriptor getDescriptor()
throws java.sql.SQLException;

public Datum[] getOracleArray()
throws SQLException;

public Datum[] getOracleArray(long l, int i)
throws SQLException;

public String getSQLTypeName()
throws java.sql.SQLException;

public int length()
throws java.sql.SQLException;

public double[] getDoubleArray()
throws java.sql.SQLException;

public double[] getDoubleArray(long l, int i)
throws java.sql.SQLException;

public float[] getFloatArray()
throws java.sql.SQLException;

public float[] getFloatArray(long l, int i)
throws java.sql.SQLException;

public int[] getIntArray()
throws java.sql.SQLException;

public int[] getIntArray(long l, int i)
throws java.sql.SQLException;

public long[] getLongArray()
throws java.sql.SQLException;

public long[] getLongArray(long l, int i)
throws java.sql.SQLException;

weblogic.jdbc.vendor.oracle.OracleArray

拡張

java.sql.Arrayの拡張

(続き)

(このインタフェースは非推奨。)

public short[] getShortArray()
throws java.sql.SQLException;

public short[] getShortArray(long l, int i)
throws java.sql.SQLException;

public void setAutoBuffering(boolean flag)
throws java.sql.SQLException;

public void setAutoIndexing(boolean flag)
throws java.sql.SQLException;

public boolean getAutoBuffering()
throws java.sql.SQLException;

public boolean getAutoIndexing()
throws java.sql.SQLException;

public void setAutoIndexing(boolean flag, int i)
throws java.sql.SQLException;

表6-8 OracleStructインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleStruct

拡張

java.sql.Structの拡張

(このインタフェースは非推奨。)

public Object[] getAttributes()
throws java.sql.SQLException;

public Object[] getAttributes(java.util.Dictionary map)
throws java.sql.SQLException;

public Datum[] getOracleAttributes()
throws java.sql.SQLException;

public oracle.sql.StructDescriptor getDescriptor()
throws java.sql.SQLException;

public String getSQLTypeName()
throws java.sql.SQLException;

public void setAutoBuffering(boolean flag)
throws java.sql.SQLException;

public boolean getAutoBuffering()
throws java.sql.SQLException;

表6-9 OracleRefインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleRef

拡張

java.sql.Refの拡張

(このインタフェースは非推奨。)

public String getBaseTypeName()
throws SQLException;

public oracle.sql.StructDescriptor getDescriptor()
throws SQLException;

public oracle.sql.STRUCT getSTRUCT()
throws SQLException;

public Object getValue()
throws SQLException;

public Object getValue(Map map)
throws SQLException;

public void setValue(Object obj)
throws SQLException;

表6-10 OracleThinBlobインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleThinBlob

拡張

java.sql.Blobの拡張

(このインタフェースは非推奨。)

int getBufferSize()throws java.sql.Exception

int getChunkSize()throws java.sql.Exception

int putBytes(long, int, byte[])throws java.sql.Exception

int getBinaryOutputStream()throws java.sql.Exception

表6-11 OracleThinClobインタフェース(非推奨)

拡張

メソッド・シグネチャ

weblogic.jdbc.vendor.oracle.OracleThinClob

拡張

java.sql.Clobの拡張

(このインタフェースは非推奨。)

public OutputStream getAsciiOutputStream()
throws java.sql.Exception;

public Writer getCharacterOutputStream()
throws java.sql.Exception;

public int getBufferSize() throws java.sql.Exception;

public int getChunkSize() throws java.sql.Exception;

public char[] getChars(long l, int i)
throws java.sql.Exception;

public int putChars(long start, char myChars[])
throws java.sql.Exception;

public int putString(long l, String s)
throws java.sql.Exception;

Oracle Thin Driverでのバッチ処理の使用

特定の状況下で、Oracle Thin Driverはバッチ・サイズに到達しない間、DBMSに更新を送信せず、文が閉じられるまで待機する場合があります。

プリペアド文を閉じると、WebLogic Serverは文を閉じずに標準JDBC状態に返します。続いて文を接続のキャッシュに戻すため、次に必要な時に文を再配信できます。

すべての更新が確実に配信されるようにするには、文または接続を閉じる前に、文を最後に使用した後でsendBatch()を明示的に呼び出す必要があります。

Oracle仮想プライベート・データベースを使用したプログラミング

Oracle仮想プライベート・データベース(Oracle Virtual Private Database: VPD)は、サーバーによって強制されるアプリケーション定義のファイン・グレイン・アクセス制御と、Oracleデータベース・サーバーのセキュアなアプリケーション・コンテキストを組み合わせたものです。WebLogic ServerアプリケーションでVPDを使用するには、以下の手順に従います。

1. WebLogic Server構成でOracle Thinドライバを使用するJDBCデータ・ソースを作成します。Oracle WebLogic Server管理コンソール・ヘルプの第2章「アプリケーションでのWebLogic JDBCの使用方法」またはJDBCデータ・ソースの作成を参照してください。

注意:
XA対応のJDBCドライバを使用している場合、KeepXAConnTillTxComplete=trueに設定する必要があります。Oracle WebLogic Server管理コンソール・ヘルプの「JDBCデータ・ソース: 構成: 接続プール」を参照してください。

2. アプリケーションで次のコードを実行します。

import weblogic.jdbc.extensions.WLConnection
// get a connection from a WLS JDBC data source
Connection conn = ds.getConnection();
// Get the underlying vendor connection object
oracle.jdbc.OracleConnection orConn = (oracle.jdbc.OracleConnection)
(((WLConnection)conn).getVendorConnection());
// Set CLIENT_IDENTIFIER (which will be accessible from
// USERENV naming context on the database server side)
orConn.setClientIdentifier(clientId);
/* perform application specific work, preferably using conn instead of orConn */
// clean up connection before returning to WLS JDBC data source
orConn.clearClientIdentifier(clientId);
// As soon as you are finished with vendor-specific calls,
// nullify the reference to the physical connection.
orConn = null;
// close the pooled connection
conn.close();

注意:
このコードでは、プールされた(論理的な)接続から得た基底の物理的な接続を使用します。

WebLogic ServerでのOracle VPDの使用

WebLogic Serverでは、oracle.jdbc.OracleConnection.setClientIdentitfierメソッドとoracle.jdbc.OracleConnection.clearClientIndentifierメソッドがサポートされています。これらを使用すると、プールされた接続から基底の物理的接続を使用せずに済みます。WebLogic ServerアプリケーションでVPDを使用するには、以下の手順に従います。

import weblogic.jdbc.vendor.oracle.OracleConnection;
// get a connection from a WLS JDBC data source
Connection conn = ds.getConnection();
// cast to the Oracle extension and set CLIENT_IDENTIFIER
// (which will be accessible from USERENV naming context on
//  the database server side)
((weblogic.jdbc.vendor.oracle.OracleConnection)conn).setClientIdentifier(clientId);
/* perform application specific work */
// clean up connection before returning to WLS JDBC data source
((OracleConnection)conn).clearClientIdentifier(clientId);
// close the connection
conn.close();

7 データ・ソースからの物理的な接続の取得

この章では、データ・ソースから物理的な接続に直接アクセスする方法について説明します。どうしても必要な場合以外は、物理的なJDBC接続へ直接アクセスすることはお薦めしません。

一般的には、WebLogic Serverによって提供される汎用JDBC接続(ラップされた物理的な接続)に対する接続のキャストを行います。これにより、サーバー・インスタンスは接続プールに対する接続の管理、接続プール機能の有効化、およびアプリケーションに提供される接続の品質維持ができるようになります。場合によって、DBMSは物理的な接続(実際のベンダーのJDBC接続)の直接アクセスを必要とする、標準以外の追加のJDBC関連クラスを提供しています。接続プール内の物理的な接続に直接アクセスするには、getVendorConnectionを使用して接続をキャストする必要があります。

注意:
Oracleでは、物理的な接続getVendorConnectionSafeにアクセスするための別のメカニズムも提供します。このメカニズムでも、プールされているデータベース接続(論理接続)からベースとなる物理接続(ベンダー接続)が返されます。ただし、接続を閉じると、「影響のある接続の削除を有効化」の設定に関係なく、プールに返されます。詳細は、「getVendorConnectionSafe」を参照してください。

次の項では、物理的な接続の取得について説明します。

- 接続を開く

- 接続を閉じる

- 物理的な接続の使用に関する制限

注意:
どうしても必要な場合以外は、物理的なJDBC接続へ直接アクセスすることはお薦めしません。

接続を開く

物理的なデータベース接続を取得するには、最初に接続プールから接続を取得してから、次のいずれかを実行します。

- 物理的な接続を必要とするメソッド内で、物理的な接続を暗黙的に渡します(getVendorConnectionを使用)。

- 接続をWLConnectionにキャストし、getVendorConnectionを呼び出します。

物理的なデータベース接続の直接アクセスは、常にベンダー固有の呼出しの場合に限定します。それ以外のすべての状況では、WebLogic Serverによって提供される汎用JDBC接続を使用します。ベンダー固有の呼出しに対する接続を開くサンプル・コードを次に示します。

例7-1 ベンダー固有の呼出しに対する接続を開くサンプル・コード

//Import this additional class and any vendor packages
//you may need.
import weblogic.jdbc.extensions.WLConnection
.
.
.
myJdbcMethod()
{
// Connections from a connection pool should always be
// method-level variables, never class or instance methods.
Connection conn = null;
try {
ctx = new InitialContext(ht);
// Look up the data source on the JNDI tree and request
// a connection.
javax.sql.DataSource ds
= (javax.sql.DataSource) ctx.lookup ("myDataSource");
// Always get a pooled connection in a try block where it is
// used completely and is closed if necessary in the finally
// block.
conn = ds.getConnection();
// You can now cast the conn object to a WLConnection
// interface and then get the underlying physical connection.
java.sql.Connection vendorConn =
((WLConnection)conn).getVendorConnection();
// do not close vendorConn
// You could also cast the vendorConn object to a vendor
// interface, such as:
// oracle.jdbc.OracleConnection vendorConn = (OracleConnection)
// ((WLConnection)conn).getVendorConnection()
// If you have a vendor-specific method that requires the
// physical connection, it is best not to obtain or retain
// the physical connection, but simply pass it implicitly
// where needed, eg:  //vendor.special.methodNeedingConnection(((WLConnection)conn)).getVendorConnection());

接続を閉じる

JDBCでの作業が完了したら、論理的な接続を閉じて、プールに戻す必要があります。物理的な接続を使い終わったら、次の操作を行います。

- 接続から取得したすべてのオブジェクトを閉じます。

- 物理的な接続は閉じません。物理的な接続はnullに設定します。

接続をどのように閉じるかは、管理コンソールで「影響のある接続の削除を有効化」プロパティの値を設定して指定します。これらのオプションの詳細は、Oracle WebLogic Server管理コンソール・ヘルプの「JDBCデータ・ソース: 構成: 接続プール」ページまたは「Oracle WebLogic Server MBean Reference」のJDBCConnectionPoolParamsBeanを参照してください。

注意:
「影響のある接続の削除を有効化」プロパティは、明示的にgetVendorConnectionを呼び出すアプリケーションに対してのみ適用されます。

例7-2 ベンダー固有の呼出しに対する接続を閉じるサンプル・コード

// As soon as you are finished with vendor-specific calls,
// nullify the reference to the connection.
// Do not keep it or close it.
// Never use the vendor connection for generic JDBC.
// Use the logical (pooled) connection for standard JDBC.
vendorConn = null;
... do all the JDBC needed for the whole method...
// close the logical (pooled) connection to return it to
// the connection pool, and nullify the reference.
conn.close();
conn = null;
}
catch (Exception e)
{
// Handle the exception.
}
finally
{
// For safety, check whether the logical (pooled) connection
// was closed.
// Always close the logical (pooled) connection as the
// first step in the finally block.
if (conn != null) try {conn.close();} catch (Exception ignore){}
}
}

「影響のある接続の削除を有効化」がTrueの場合

影響のある接続の削除を有効化がtrue(デフォルト値)のときに論理的な接続を閉じると、サーバー・インスタンスは基底の物理的接続を破棄して、それに取って代わる新しい接続を作成します。このアクションで、プールは次のユーザーに対して、そのユーザーがプール接続の唯一のユーザーであることを確実に保証できるようになります。この構成により、接続を閉じるための簡単で安全な方法がもたらされます。ただし、以下の理由により、パフォーマンス上の損失が生じます。

- 物理的な接続は接続プールの新しいデータベース接続で置き換えられます。このため、アプリケーション・サーバーとデータベース・サーバーの両方でリソースが使用されます。

- 元の接続のStatementキャッシュが閉じられて、新しい接続用に新しいキャッシュが開かれます。したがって、Statementキャッシュを使用する際のパフォーマンスの利点は失われます。

「影響のある接続の削除を有効化」がFalseの場合

「影響のある接続の削除を有効化」をfalseで使用するのは、公開されている物理的な接続が、論理的な接続を閉じた後、保持または再利用されることが絶対にないと確信している場合のみです。

「影響のある接続の削除を有効化」がfalseのときに論理的な接続を閉じると、サーバー・インスタンスは単に物理的な接続を、再利用のために接続プールに返します。この構成では、パフォーマンス上の損失は最小限に抑えられますが、サーバー・インスタンスは、接続の品質や、論理的な接続が閉じられた後の接続管理の効率を保証はしません。接続が接続プールに返される前に、その接続が他のアプリケーションによる再利用に適していることを確認する必要があります。

物理的な接続の使用に関する制限

接続プールの論理的な接続の代わりに物理的な接続を使用することはお薦めしません。ただし、たとえばSTRUCTの作成などに、物理的な接続を使用する必要がある場合は、以下の負担と制限を考慮してください。

- 物理的な接続はサーバー側コードでのみ使用できます。

- 物理的な接続を使用する場合、エラー処理や文のキャッシングなど、WebLogic Serverが提供する接続管理の利点がすべて失われます。

- 物理的な接続は、それを必要とするベンダー固有のメソッドまたはクラスにのみ使用します。汎用JDBC (文やトランザクション呼出しの作成など)には物理的な接続を使用しないでください。

8 WebLogic ServerにおけるRowSetの使い方

この章では、WebLogic RowSetの特性と使用法について説明します。

- RowSetについて

- RowSetの種類

- RowSetを使用したプログラミング

- CachedRowSet

- RowSetに対するデータベース更新用メタデータの設定

- メタデータを扱うためのWebLogic RowSet拡張

- RowSetとトランザクション

- FilteredRowSet

- WebRowSet

- JoinRowSet

- JDBCRowSet

- SyncResolverを使用したSyncProviderExceptionの処理

- WLCachedRowSet

- SharedRowSet

- SortedRowSet

- SQLPredicate、SQL方式のRowSetフィルタ

- オプティミスティックな同時実行性ポリシー

- パフォーマンスのオプション

RowSetについて

WebLogic Serverには、JSR-114の仕様に準拠したJava RowSetが実装されています。仕様の詳細は、http://www.oracle.com/technetwork/java/javase/jdbc/index.htmlを参照してください。WebLogicのRowSet実装には、RowSet仕様の拡張も含まれています。こうした拡張を使用すると、アプリケーションでRowSetをより有効に活用できます。

RowSetはJava ResultSetの拡張です。ResultSetと同様、RowSetも表形式のデータを保持するJavaオブジェクトです。ただし、RowSetではResultSet機能に大幅な柔軟性が加えられていて、ResultSetの持つ制限の一部が緩和されたり削減されたりしています。

RowSetの種類

WebLogic ServerのRowSet実装には、以下のような種類とユーティリティがあります。

標準のRowSet :

- CachedRowSet

- FilteredRowSet

- WebRowSet

- JoinRowSet

- JDBCRowSet

WebLogicのRowSet拡張 :

- WLCachedRowSet

- SharedRowSet

- SortedRowSet

- SQLPredicate、SQL方式のRowSetフィルタ

RowSetを使用したプログラミング

WebLogic ServerのRowSet実装は、ユーザーが以下の手順でRowSetを扱うことを想定して設計されています。

1. RowSetを作成して構成します(問合せ、データベース接続、その他のプロパティを定義します)。

2. RowSetにデータを入力します(問合せパラメータを指定して問合せを実行します)。

3. 必要に応じてRowSetメタデータを指定します。

4. 必要に応じてRowSetにフィルタまたはソーターを設定します。

5. RowSet内のデータを操作します(挿入、更新、削除を行います)。

6. RowSetからデータベースへのデータ変更の同期を行います。

変更を同期した後には、アプリケーションの設計に応じて手順2または手順3から繰返し処理を行えます。「トランザクション完了後のWebLogic RowSetの再利用」を参照してください。

WebLogicのRowSet実装にはライフ・サイクルのフレームワークがあり、これによってRowSetオブジェクトが異常な状態にならないようにしています。WebLogic Serverでは、上記の処理段階に応じて、内部的にRowSetに対しライフ・サイクル・ステージが設定されます。データ損失のリスクを減らすため、ライフ・サイクル・ステージに応じてRowSetに実施できる操作が制限されます。たとえばRowSetのステージが「Updating」(更新)の場合、RowSetに対して呼び出せるのは、updateXXX()メソッド(updateString()、updateInt()など)のみです。この制限は、updateRow()を呼び出して更新のフェーズが完了するまで適用されます。

重要な注意事項を以下に示します。

- 保留中の変更がある場合、RowSetに対して再入力、フィルタ、ソートは行えません。データの変更が不測の事態によって失われることを防ぐため、RowSetのデータを変更してもその変更がデータベースとの間で同期されていない場合はRowSetに対してこれらの操作ができないようになっています。

- カーソルが暗黙的に移動することはありません。行から行へ明示的にカーソルを移動する必要があります。

- RowSetのライフ・サイクル・ステージは内部的なプロセスです。ライフサイクルのステージにアクセスするためのパブリックAPIはありません。ライフサイクルのステージをユーザーが設定することはできません。acceptChanges()またはrestoreOriginal()を呼び出すとRowSetのライフ・サイクル・ステージは終了し、再び処理を開始できます。

注意:
クライアント側アプリケーションでRowSetを使用する際は、サーバーとクライアントの両方のCLASSPATHに、同一のJDBCドライバ・クラスを指定する必要があります。ドライバ・クラスが一致していないと、java.rmi.UnmarshalException例外がスローされる場合があります。

RowSetの作成時からデータ変更がデータベースとの間で同期されるまでのRowSetのライフ・サイクル・ステージの実例については、例8-1のコメントを参照してください。

CachedRowSet

以下の節では、WebLogic Serverにおける標準のCachedRowSetの使い方について説明します。

- 特性

- CachedRowSetに特有のプログラミング上の考慮事項と制限

- サンプル・コード

- CachedRowSetのクラスとインタフェースのインポート

- CachedRowSetの作成

- CachedRowSetのプロパティの設定

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

- CachedRowSetへの入力

- CachedRowSetへのメタデータの設定

- CachedRowSetのデータの操作

- RowSetの変更をデータベースとの間で同期する

また、標準のCachedRowSetオブジェクトのWebLogic拡張の使用方法については、「WLCachedRowSet」を参照してください。

特性

CachedRowSetは接続されていないResultSetオブジェクトです。CachedRowSetのデータはメモリーに格納されます。WebLogic Server実装のCachedRowSetには以下の特性があります。

- データの挿入、更新、削除に使用できます。

- シリアライズ可能なため、モバイル機器などの様々なアプリケーション・コンポーネントに渡すことができます。

- トランザクション処理に対応しているためRowSetを再利用できます。「トランザクション完了後のWebLogic RowSetの再利用」を参照してください。

- RowSetでのデータ変更をデータベースとの間で同期するためにオプティミスティックな同時実行性制御が使用されます。

- SyncProvider例外から得られるSyncResolverオブジェクトを使用して、RowSetでのデータ変更とデータベース間の競合を解決します。「SyncResolverを使用したSyncProviderExceptionの処理」を参照してください。

CachedRowSetに特有のプログラミング上の考慮事項と制限

アプリケーションの設計時には、次のことを考慮するようにします。

- RowSetの問合せ結果はすべてメモリーに格納される

- データの競合

RowSetの問合せ結果はすべてメモリーに格納される

CachedRowSetではデータベースへの接続が保持されないので、すべての問合せの結果は必ずメモリーに格納されます。問合せの結果が非常に大きいと、メモリー不足エラーによりパフォーマンスが低下することがあります。大きなデータ・セットの場合、ResultSetを使用する方が適していることもあります。ResultSetではデータベースへの接続が保持されるため、問合せ結果の一部をメモリーに保持してから必要に応じてデータベースに戻り、さらに行を取得できるためです。

データの競合

CachedRowSetは、RowSetへの入力からRowSet内のデータ変更がデータベースとの間で同期されるまでの間に、別のプロセスで更新されることがあまりないようなデータに使用するのがもっとも適しています。この期間にデータベースが変更されるとデータの競合が発生します。データの競合を検出して処理する方法については、「SyncResolverを使用したSyncProviderExceptionの処理」を参照してください。

サンプル・コード

例8-1にCachedRowSetの基本的なワークフローを示します。この例では、主要な各操作と対応するRowSetのライフ・サイクル・ステージについてコメントを使って説明します。このサンプル・コードの後で、サンプルの主要な各セクションについてさらに詳細に説明します。

例 8-1 CachedRowSetのサンプル・コード

import javax.sql.rowset.CachedRowSet;
import weblogic.jdbc.rowset.RowSetFactory;
public class CachedRowSetDemo {
public static void main (String[] args) {
//DESIGNING lifecycle stage - Create the rowset and set properties
try {
//Create a RowSetFactory instance.
RowSetFactory rsfact = RowSetFactory.newInstance();
CachedRowSet rs = rsfact.newCachedRowSet();
//Set database access through a DataSource.
rs.setDataSourceName(examples-dataSource-demoPool);
//See  Database Connection Options for more options.
//Set query command
rs.setCommand("SELECT ID, FIRST_NAME, MIDDLE_NAME, LAST_NAME,
PHONE, EMAIL FROM PHYSICIAN WHERE ID>?");
//CONFIGURE QUERY lifecycle operation
rs.setInt(1, 0);
//POPULATING lifecycle stage - Execute the command to populate the rowset
rs.execute();
}
//CONFIGURING METADATA - Populate first, then set MetaData,
//including KeyColumns
rs.setKeyColumns(new int[] { 1 });
while (rs.next ()) //NAVIGATING lifecycle stage
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
}
}
//Working with data
//Delete rows in the rowset
try {
//MANIPULATING lifecycle stage - navigate to a row
//(manually moving the cursor)
rs.last();
rs.deleteRow();
//Note that the database is not updated yet.
}
//Update a row in the rowset
try {
//MANIPULATING lifecycle stage - navigate to a row
//(manually moving the cursor)
rs.first();
//UPDATING lifecycle stage - call an update() method
rs.updateString(4, "Francis");
//MANIPULATING lifecycle stage - finish update
rs.updateRow();
//Note that the database is not updated yet.
}
//INSERTING lifecycle stage - Insert rows in the rowset
try {
rs.moveToInsertRow();
rs.updateInt(1, 104);
rs.updateString("FIRST_NAME", "Yuri");
rs.updateString("MIDDLE_NAME", "M");
rs.updateString("LAST_NAME", "Zhivago");
rs.updateString("PHONE", "1234567812");
rs.updateString("EMAIL", "Yuri@poet.com");
rs.insertRow(); //"Finish Update" action;
//MANIPULATING lifecycle stage - navigate to a row
rs.moveToCurrentRow();
//Note that the database is not updated yet.
}
//Send all changes (delete, update, and insert) to the database.
//DESIGNING or POPULATING lifecycle stage - after synchronizing changes
//with the database, lifecycle stage depends on other environment settings.
//See  Reusing a WebLogic RowSet After Completing a Transaction.
try {
rs.acceptChanges();
rs.close();
}
}

CachedRowSetのクラスとインタフェースのインポート

標準のRowSetを使用するには、次のクラスをインポートする必要があります。

javax.sql.rowset.CachedRowSet;
weblogic.jdbc.rowset.RowSetFactory;

CachedRowSetの作成

RowSetはファクトリ・インタフェースから作成されます。WebLogic ServerでRowSetを作成するには、主に以下の手順に従います。

1. RowSetFactoryインスタンスを作成します。このインスタンスはアプリケーションで使用するRowSetオブジェクトを作成するためのファクトリとして機能します。RowSetFactoryのデータベース接続のプロパティを指定すると、同じデータベース接続を使用する複数のRowSetを少ないコード行で作成できます。

RowSetFactory rsfact = RowSetFactory.newInstance();

2. WLCachedRowSetを作成してjavax.sql.rowset.CachedRowSetオブジェクト型にキャストします。デフォルトではWebLogic newCachedRowSet() RowSetFactoryメソッドでWLCachedRowSetオブジェクトが作成されます。このオブジェクトをそのまま使用することもできますが、標準のCachedRowSetオブジェクトを使用する場合は、オブジェクトをCachedRowSetとしてキャストできます。

CachedRowSet rs = rsfact.newCachedRowSet();

CachedRowSetのプロパティの設定

RowSetには、同時実行性の種類、データ・ソースの名前、トランザクション分離レベルなど数多くのプロパティがあります。これらのプロパティを設定してRowSetの動作を決定できます。RowSetの特定の用途に応じて必要なプロパティのみを設定する必要があります。利用可能なプロパティについては、http://download.oracle.com/javase/6/docs/api/javax/sql/rowset/BaseRowSet.htmlのjavax.sql.rowset.BaseRowSetクラスのJavadocを参照してください。

データベース接続のオプション

ほとんどのアプリケーションでは、データベースからのデータをRowSetに入力します。RowSetとデータベースとの接続は、以下のいずれかの方法で設定します。

- データ・ソースを使用して自動的に接続する - setDataSourceName()メソッドを使用して、JDBCデータ・ソースのJNDI名を指定できます。execute()およびacceptChanges()を呼び出すと、RowSetでデータ・ソースからのデータベース接続が取得され、それが使用されて、データ・ソースの接続のプールに戻されます。これは、推奨される方法です。

rs.setDataSourceName(examples-dataSource-demoPool);

- データベース接続を手動で取得する - RowSetで必要になる前にアプリケーションでデータベース接続を取得してから、接続オブジェクトをexecute()メソッドおよびacceptChanges()メソッドのパラメータとして渡します。必要に応じて接続を閉じる必要もあります。

//Lookup DataSource and get a connection
ctx = new InitialContext(ht);
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("myDS");
conn = ds.getConnection();

//Pass the connection to the rowset
rs.execute(conn);

JDBCデータ・ソースの詳細については、「DataSourceオブジェクトからのデータベース接続の取得」を参照してください。

- JDBCドライバをロードして直接的に接続する - JDBCドライバをロードして適切なプロパティを設定すると、RowSetではexecute()およびacceptChanges()を呼び出したときにデータベース接続が作成されます。RowSetでは接続を使用し終えるとすぐにその接続が閉じられます。RowSetではexecute()メソッド呼出しとacceptChanges()メソッド呼出しの間、接続は保持されません。

Class.forName("org.apache.derby.jdbc.ClientDriver");
rs.setUrl("jdbc:derby://localhost:1527/demo");
rs.setUsername("examples");
rs.setPassword("examples");
rs.execute();

- RowSetFactoryの接続のプロパティを設定する - RowSetFactoryのデータベース接続のプロパティを設定すると、RowSetFactoryから作成されたすべてのRowSetでその接続のプロパティが継承されます。データ・ソースをルックアップしてからsetDataSource()メソッドでRowSetFactoryのデータ・ソースのプロパティを設定するのが、推奨される方法です。

//Lookup DataSource and get a connection
ctx = new InitialContext(ht);
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("myDS");

//Set the datasource property on the RowSetFactory
rsfact.setDataSource(ds);

CachedRowSetへの入力

RowSetへのPopulating(入力)とは、RowSetにデータの行を格納する作業のことをいいます。通常、このデータの取得元はリレーショナル・データベースです。データベースからのデータは、以下のいずれかの方法でRowSetに入力できます。

- setCommand()メソッドでSQLコマンドを設定してから、execute()メソッドでそのコマンドを実行します。

rs.setCommand("SELECT ID, FIRST_NAME, MIDDLE_NAME, LAST_NAME,
PHONE, EMAIL FROM PHYSICIAN");
rs.execute();

- 既存の結果セットからpopulate()メソッドを使用して入力します。

rs.populate(resultSet);

注意:
ResultSet.TYPE_FORWARD_ONLYの結果セットを使用している場合、以下の条件で行セットに入力しようとするとSQLExceptionがスローされます。

- 結果セットのカーソルが行1を超える位置にある状態でCachedRowset.populate(ResultSet rs)を呼び出した場合。

- newPositionの値が結果セットの現在のカーソル位置より小さい状態でCachedRowset.populate(ResultSet rs, int newPosition)を呼び出した場合。

CachedRowSetへのメタデータの設定

RowSetのデータ変更をデータベースとの間で同期するために、RowSetにメタデータを設定することが必要な場合もあります。詳細については、「RowSetに対するデータベース更新用メタデータの設定」を参照してください。

CachedRowSetのデータの操作

キャッシュされたRowSetに一連のデータ行を入力した後には、結果セットのデータを扱うのとほぼ同じ方法でそのキャッシュ済みのデータを取り扱えます。ただし、データベースに対して変更を行う前には、acceptChanges()を明示的に呼び出す必要があります。

注意:
RowSetの列名や表名に区切り識別子は使用できません。SQL文の中では、区切り識別子は二重引用符で囲む必要があります。区切り識別子には、SQL予約語(USERやDATEなど)になっているものや、識別子ではない名前になっているものがあります。有効な識別子は必ず文字で始まり、文字、数字、およびアンダースコアのみを使用できます。

RowSetの行からデータを取得する

RowSetからデータを取得するには、結果セットの場合と同様にgetXXXメソッドを使用します。次に例を示します。

while (rs.next ())
{
int id = rs.getInt (1);
String fname = rs.getString ("FIRST_NAME");
String mname = rs.getString ("MIDDLE_NAME");
String lname = rs.getString ("LAST_NAME"));
}

RowSetの行を更新する

通常、データの更新は以下の手順で行います。

1. 行または挿入行に移動します。

2. updateXXXメソッドで行を変更します。

3. updateRow()またはinsertRow()で操作を完了します。

操作を完了しても変更はデータベースとの間で同期されないことに注意します。変更はRowSetに対してのみ行われます。acceptChanges()を呼び出して、明示的に変更を同期させる必要があります。詳細については、下記の「RowSetの変更をデータベースとの間で同期する」を参照してください。

RowSetを操作する際、WebLogic Serverでは内部的に各操作の後でRowSetにライフ・サイクル・ステージが設定され、その後は現在のライフ・サイクル・ステージに基づいてRowSetに対する以降の操作が制限されます。updateメソッド群で行の変更を開始したら、必ずupdateRow()またはinsertRow()で操作を完了します。完了してはじめて、別の行の操作(別の行へのカーソルの移動を含む)ができるようになります。RowSetのライフ・サイクル・ステージと、各ステージで許可される操作の詳細については、「RowSetを使用したプログラミング」を参照してください。

行を更新するには、更新する行にカーソルを移動して、その行の個別の列に対してupdateXXXメソッドを呼び出してから、updateRow()を呼び出して操作を完了します。次に例を示します。

rs.first();
rs.updateString(4, "Francis");
rs.updateRow();

注意:
複数の表の同名の列を更新する場合、列の参照にはUpdate文で列の索引番号を使用する必要があります。

RowSetに行を挿入する

行を挿入するには、新規の挿入行にカーソルを移動してその行の列の値を更新してから、insertRow()を呼び出してRowSetに行を追加します。次に例を示します。

rs.moveToInsertRow();
rs.updateInt(1, 104);
rs.updateString("FIRST_NAME", "Yuri");
rs.updateString("MIDDLE_NAME", "M");
rs.updateString("LAST_NAME", "Zhivago");
rs.updateString("PHONE", "1234567812");
rs.updateString("EMAIL", "Yuri@poet.com");
rs.insertRow();
rs.moveToCurrentRow();

行を挿入した後には、明示的にカーソルを移動する必要があります。カーソルが暗黙的に移動することはありません。

RowSetの行を削除する

RowSetの行を削除するには、カーソルをその行に移動してdeleteRow()を呼び出します。次に例を示します。

rs.last();
rs.deleteRow();

RowSetの変更をデータベースとの間で同期する

RowSetの個別の行を変更した後には、acceptChanges()を呼び出して変更をデータベースに伝播します。次に例を示します。

rs.acceptChanges();

acceptChanges()を呼び出すと、RowSetでは、すでにRowSetで使用されているデータベース接続情報を使用するか(「データベース接続のオプション」を参照)、acceptChanges(connection)メソッドで渡された接続オブジェクトを使用して、データベースに接続します。1つまたは複数の行を変更した後にacceptChanges()を呼び出せます。RowSetに対してすべての変更を行った後にacceptChanges()を呼び出すと、RowSetからデータベースへの接続が1度だけになるのでより効率的です。

WebLogic ServerでRowSetを使用する場合、データベースに対する書込みと読取りにはweblogic.jdbc.rowset.WLSyncProviderオブジェクトが内部的に使用されます。WLSyncProviderではデータベースの変更にオプティミスティックな同時実行性が使用されます。つまり、RowSetへの入力時からRowSetのデータの変更がデータベースに伝播されるまでの間に、データベースのデータが別のプロセスによって変更されないと仮定されます。データベースに変更を書き込む前には、WLSyncProviderによってデータベースのデータとRowSetの元の値(RowSetの作成時または最後の同期の際にRowSetに読み込まれた値)が比較されます。データベースの値になんらかの変更があった場合にはjavax.sql.rowset.spi.SyncProviderExceptionがスローされ、データベースにはどの変更も書き込まれません。アプリケーションでこの例外を捕捉して、処理方法を決定できます。詳細については、「SyncResolverを使用したSyncProviderExceptionの処理」を参照してください。

WLCachedRowSetインタフェースはCachedRowSetインタフェースの拡張で、このインタフェースでオプティミスティックな同時実行性ポリシーを選択できます。詳細については、「オプティミスティックな同時実行性ポリシー」を参照してください。

変更をデータベースに伝播した後には、アプリケーションの環境に応じてRowSetのライフ・サイクル・ステージが「Designing」(設計)または「Populating」(入力)に変わります。「Designing」(設計)ステージの場合、再び使用する前にRowSetに再入力する必要があります。「Populating」(入力)ステージの場合、現在のデータを持つRowSetを使用できます。詳細については、「トランザクション完了後のWebLogic RowSetの再利用」を参照してください。

RowSetを再び使用する予定がない場合は、close()メソッドで閉じる必要があります。次に例を示します。

rs.close();

RowSetに対するデータベース更新用メタデータの設定

SQL問合せでRowSetに入力する場合、WebLogicのRowSet実装ではResultSetMetaDataインタフェースを使用して、自動的にRowSet内のデータの表名と列名が認識されます。ほとんどの場合、RowSetが変更をデータベースに書き戻すために必要なSQLを生成するには、この情報で十分です。ただし一部のJDBCドライバでは、この問合せで返される行に表および列のメタデータが含まれません。RowSetのデータ変更をデータベースとの間で同期しようとすると、次のエラーが表示されます。

java.sql.SQLException: Unable to determine the table name for column:
column_name. Please ensure that you've called WLRowSetMetaData.setTableName to
set a table name for this column.

表名がない場合、RowSetは読込み操作にのみ使用できます。表名をプログラム的に指定しない限り、RowSetでは更新を発行できません。また、setKeyColumns()メソッドによる主キー列の設定が必要な場合もあります。次に例を示します。

rs.setTableName(PHYSICIAN);
rs.setKeyColumns(new int[] { 1 });

詳細については、javax.sql.rowset.CachedRowSetインタフェースの説明を参照してください。

メタデータを扱うためのWebLogic RowSet拡張

以下の節では、RowSetに対する適切なメタデータの取得または設定に使用できるWebLogic RowSet拡張について説明します。

- executeAndGuessTableNameとexecuteAndGuessTableNameAndPrimaryKeys

- MetaDataインタフェースを使用した表および主キー情報の設定

- 書込み表の設定

executeAndGuessTableNameとexecuteAndGuessTableNameAndPrimaryKeys

SQL問合せでRowSetに入力する場合、通常はexecute()メソッドを使用して問合せを実行し、データを読み込みます。WLCachedRowSet実装には、関連付けられた表のメタデータも識別するためにexecuteメソッドを拡張したexecuteAndGuessTableNameメソッドおよびexecuteAndGuessTableNameAndPrimaryKeysメソッドが用意されています。

executeAndGuessTableNameメソッドでは、関連付けられたSQLを解析して、すべての列の表名を、SQLキーワードFROMに続く最初の語として設定します。

executeAndGuessTableNameAndPrimaryKeysメソッドは、SQLコマンドを解析して表名を読み取ります。続いて、java.sql.DatabaseMetaDataを使用して表の主キーを判定します。

注意:
これらのメソッドはDBMSまたはJDBCドライバのサポートに依存しています。すべてのDBMS、すべてのJDBCドライバで機能するとは限りません。

MetaDataインタフェースを使用した表および主キー情報の設定

WLRowSetMetaDataインタフェースを使用して表および主キー情報を手動で設定することもできます。

WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
// Sets one table name for all columns
metaData.setTableName("employees");

または

metaData.setTableName("e_id", "employees");
metaData.setTableName("e_name", "employees");

WLRowSetMetaDataインタフェースを使用して主キー列を指定することもできます。

metaData.setPrimaryKeyColumn("e_id", true);

詳細については、weblogic.jdbc.rowset.WLRowSetMetaDataのJavadocを参照してください。

書込み表の設定

WLRowSetMetaDataインタフェースには、更新または削除する表のみを指定するためのsetWriteTableNameメソッドがあります。このメソッドは通常、複数の表の結合が入力されているRowSetにおいて、1つの表のみを更新する場合に使用します。書込み表に属さない列は読取り専用としてマークされます。

たとえば、RowSetに「注文」と「顧客」の結合が含まれるとします。書込み表を「注文」に設定します。deleteRowを呼び出すと、「注文」の行は削除されますが、「顧客」の行は削除されません。

注意:
JSR-114は、WebLogic CachedRowSetMetaData.setWriteTableNameメソッドと同じ機能を備えたCachedRowSet.setTableName (http://download.oracle.com/javase/6/docs/api/javax/sql/rowset/CachedRowSet.html#setTableName(java.lang.String)を参照)を提供します。どちらのメソッドを呼び出しても、書込み表に属さない列が読取り専用のものとしてマークされます。WebLogicではまた、列がどの表に属するかのマッピングに使用されるCachedRowSetMetaData.setTableNameメソッドが用意されています。setTableNameを使用して書込み表を設定する際には、アプリケーションに適したAPIを使用してメソッドを実装するように注意してください。

RowSetとトランザクション

ほとんどのデータベースやJDBCアプリケーションではトランザクションを使用します。RowSetはJTAトランザクションを含むトランザクションをサポートしています。一般的な使用例は次のとおりです。トランザクション1でRowSetを取得します。トランザクション1がコミットされます。基底のデータに対して、データベースやアプリケーション・サーバーによるロックはありません。RowSetはメモリー内にデータを保持します。データを変更したり、ネットワーク経由でクライアントに提供したりできます。アプリケーションはデータベースに対する変更をコミットする場合、トランザクション2を開始して、RowSetのacceptChangesメソッドを呼び出します。その後トランザクション2がコミットされます。

JTAグローバル・トランザクションとの統合

EJBコンテナとUserTransactionインタフェースはJTAトランザクション・マネージャを使用してトランザクションを開始します。RowSetの操作はこのトランザクションに参加することができます。JTAトランザクションに参加するには、RowSetはトランザクション対応のDataSource (TxDataSource)を使用する必要があります。DataSourceはWebLogic Serverコンソールで構成できます。

acceptChangesでオプティミスティックな競合や他の例外が発生した場合、RowSetはグローバルJTAトランザクションを中止します。アプリケーションは通常データを再び読み込んで、新しいトランザクションで更新を再び処理します。

グローバル・トランザクションを使用するRowSetの動作

障害またはロールバックが発生すると、データはデータベースからロールバックされますが、RowSetからはロールバックされません。作業を進める前に、次のいずれかを行う必要があります。

- rowset.refreshを呼び出して、データベースからのデータでRowSetを更新します。

- 現在のデータで新しいRowSetを作成します。

ローカル・トランザクションの使用

JTAグローバル・トランザクションを使用しない場合、RowSetはローカル・トランザクションを使用します。最初に接続に対するsetAutoCommit(false)を呼び出します。次にSQL文をすべて発行して、最後にconnection.commit()を呼び出します。これでローカル・トランザクションをコミットしようとします。EJBまたはJMSコンテナによって開始されたJTAトランザクションと統合する場合は、このメソッドは使用しないでください。

acceptChangesでオプティミスティックな競合や他の例外が発生した場合、RowSetはローカル・トランザクションをロールバックします。この場合、acceptChangesで発行されたSQLは、いずれもデータベースにコミットされません。

ローカル・トランザクションを使用するRowSetの動作

この節では、失敗したローカル・トランザクションにおけるRowSetの動作について説明します。この動作は、接続オブジェクトの種類によって異なります。

connection.commitの呼出し

この状況では、接続オブジェクトはRowSetによって作成されたものではなく、connection.commitを呼び出すことによってローカル・トランザクションを開始します。トランザクションが失敗するか、または接続がconnection.rollbackを呼び出すと、データはデータベースからロールバックされますが、RowSetにおいてはロールバックされません。作業を進める前に、次のいずれかを行う必要があります。

- rowset.refreshを呼び出して、データベースからのデータでRowSetを更新します。

- 現在のデータで新しいRowSetを作成します。

acceptChangesの呼出し

この状況では、RowSetが独自の接続オブジェクトを作成し、それを使用してacceptChangesを呼び出すことによりRowSet内のデータを更新します。障害が発生した場合、またはRowSetがconnection.rollbackを呼び出した場合、データはRowSetからもデータベースからもロールバックされます。

トランザクション完了後のWebLogic RowSetの再利用

多くの場合、RowSetの変更をデータベースとの間で同期した後に、そのRowSetを現在入力されているデータのまま使用することが必要になるでしょう。そうすることでデータベースとの往復回数が減るため、アプリケーションのパフォーマンスを向上させることができます。ただし、RowSetとそのデータを再利用する場合、そのデータにさらに変更を加える前に、そのRowSetが参加するトランザクションが必ずすべて完了している必要があります。

ローカル・トランザクションでRowSetを使用していて、RowSetデータの変更をデータベースとの間で同期する前に、接続オブジェクトにautocommit=trueと設定されている場合、データの同期後に現在の値のままRowSetを再利用できます。これは、autocommitの設定によってローカル・トランザクションがすぐに強制的に完了するためです。RowSetの変更前には、ローカル・トランザクションが必ず完了します。

以下のいずれかの状況でRowSetを使用している場合、すべてのトランザクションが必ず自動的に完了するとは限りません。

- グローバル・トランザクションで使用している

- ローカル・トランザクションで、autocommit=falseと設定された接続オブジェクトを使用してデータの変更をデータベースと同期している

これらのいずれかの場合、現在のデータでRowSetを再利用する前に、acceptChanges()を呼び出してデータベースとの間で変更を同期した後で、tx.commit()またはjava.sql.Connection.commit()の代わりにjavax.sql.rowset.CachedRowSet.commit()を呼び出してトランザクションをコミットします。CachedRowSet.commit()メソッドにはConnection.commit()メソッドがラップされています。これを使用すると必ずトランザクションが完了され、その後にRowSetを変更できるようになります。

FilteredRowSet

以下の節では、WebLogic Serverにおける標準のFilteredRowSetの使い方について説明します。

- FilteredRowSetの特性

- 特有のプログラミング上の考慮事項

- FilteredRowSetのサンプル・コード

- FilteredRowSetのクラスとインタフェースのインポート

- FilteredRowSetの作成

- FilteredRowSetのプロパティの設定

- FilteredRowSetのデータベース接続のオプション

- FilteredRowSetへの入力

- FilteredRowSetのメタデータの設定

- FilteredRowSetに対するフィルタの設定

- FilteredRowSetのデータの操作

FilteredRowSetの特性

FilteredRowSetを使用するとキャッシュされた行のサブセットを取り扱え、データベースに接続されていない状態で行のサブセットを変更できます。フィルタ処理されたRowSetとは、分かりやすく言えば、キャッシュされているRowSetの中で、特定の行のみを閲覧、移動、操作できるものをいいます。FilteredRowSetには以下のような特性があります。

- 利用できる行は、アプリケーションで指定したjavax.sql.rowset.Predicateオブジェクトで決定され、setFilter()メソッドで指定されます。

- Predicateオブジェクトにはjavax.sql.rowset.Predicateインタフェースを実装する必要があります。Predicateインタフェースにはpublic boolean evaluate(RowSet rs)メソッドがあり、このメソッドでRowSetの各行を評価します。

- このメソッドからtrueが返された場合、その行は利用可能で閲覧することもできます。

- このメソッドからfalseが返された場合、その行は利用も閲覧もできません。

詳細については「FilteredRowSetに対するフィルタの設定」を参照してください。

- WebLogic Serverにはweblogic.jdbc.rowset.SQLPredicateクラスというjavax.sql.rowset.Predicateインタフェースの実装が用意されています。このクラスを使用すると、SQLのようなWHERE句の構文を使用してFilteredRowSetのフィルタを定義できます。「SQLPredicate、SQL方式のRowSetフィルタ」を参照してください。

特有のプログラミング上の考慮事項

- RowSetフィルタは累積的ではない

- フィルタの設定、変更前に保留中の変更を解決する

RowSetフィルタは累積的ではない

FilteredRowSetのWebLogic実装では現在、FilteredRowSetにフィルタを2回設定すると古いフィルタが新しいフィルタで置き換えられます。JSR-114にはこの点についてはっきりとした規定がありません。参照実装は同じように動作しません。RowSet内のフィルタ済の行をさらにフィルタします。この場合2回目のフィルタを変更して必要なすべての条件をフィルタするようにすると、同じ効果を得られます。

フィルタの設定、変更前に保留中の変更を解決する

RowSetフィルタを設定または変更する前にRowSetに保留中の変更がある場合、その変更を受け入れる(acceptChanges()を呼び出す)か、RowSetのデータを変更前の状態に戻す(restoreOriginal()を呼び出す)必要があります。WebLogic Serverでは行われる可能性のある変更を示せるようにRowSet内の移動が認められており、ユーザーはRowSetフィルタを変更する前に上記のどちらかのメソッドを呼び出す必要があります。acceptChanges()ではデータベースへのアクセスが行われ、restoreOriginal()では行われません。

FilteredRowSetのサンプル・コード

以下のサンプルに、キャッシュされたRowSetを作成してからWebLogic Server SQLPredicateを使用してフィルタを適用および変更する方法について示します。

例 8-2 FilteredRowSetのサンプル・コード

import javax.sql.rowset.FilteredRowSet;
import weblogic.jdbc.rowset.RowSetFactory;
import weblogic.jdbc.rowset.SQLPredicate;
public class FilteredRowSetDemo {
public static void main (String[] args) {
//DESIGNING lifecycle stage - Create the rowset and set properties
try {
//Create a RowSetFactory instance and from the factory,
//create a WLCachedRowSet and cast it to a FilteredRowSet.
RowSetFactory rsfact = RowSetFactory.newInstance();
FilteredRowSet rs = rsfact.newCachedRowSet();
//Set database access through a DataSource.
//See  Database Connection Options for more options.
rs.setDataSourceName(examples-dataSource-demoPool);
rs.setCommand("SELECT ID, FIRST_NAME, MIDDLE_NAME, LAST_NAME,
PHONE, EMAIL FROM PHYSICIAN WHERE ID>?");
//CONFIGURE QUERY lifecycle operation - set values for query parameters.
rs.setInt(1, 0);
//POPULATING lifecycle stage - Execute the command to populate the rowset
rs.execute();
}
//CONFIGURING METADATA - Populate first, then set MetaData, including KeyColumns
rs.setKeyColumns(new int[] { 1 });
while (rs.next ())
//NAVIGATE operations put the rowset in the MANIPULATING lifecycle stage
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
}
}
//Need to accept changes or call restoreOriginal to put the rowset
//into the DESIGNING or POPULATING stage.
//After navigating, the rowset is in MANIPULATING stage,
//and you cannot change properties in that lifecycle stage.
rs.restoreOriginal();
//S E T   F I L T E R
//use SQLPredicate class to create a SQLPredicate object,
//then pass the object in the setFilter method to filter the RowSet.
SQLPredicate filter = new SQLPredicate("ID >= 103");
rs.setFilter(filter);
System.out.println("Filtered data: ");
while (rs.next ())
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
System.out.println (" ");
}
//Need to accept changes or call restoreOriginal to put the rowset
//into the DESIGNING or POPULATING lifecycle stage.
//After navigating, the rowset is in MANIPULATING stage,
//and you cannot change properties in that lifecycle stage.
rs.restoreOriginal();
//C H A N G I N G   F I L T E R
SQLPredicate filter2 = new SQLPredicate("ID <= 103");
rs.setFilter(filter2);
System.out.println("Filtered data: ");
while (rs.next ())
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
System.out.println (" ");
}
//Need to accept changes or call restoreOriginal to put the rowset
//into the DESIGNING or POPULATING lifecycle stage.
//After navigating, the rowset is in MANIPULATING stage,
//and you cannot change properties in that lifecycle stage.
rs.restoreOriginal();
//R E M O V I N G   F I L T E R
rs.setFilter(null);
while (rs.next ())
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
System.out.println (" ");
}
rs.close();
}
}

FilteredRowSetのクラスとインタフェースのインポート

標準のFilteredRowSetを使用するには、次のクラスをインポートする必要があります。

javax.sql.rowset.FilteredRowSet;
weblogic.jdbc.rowset.RowSetFactory;

上記のサンプル・コードでは、フィルタの作成にweblogic.jdbc.rowset.SQLPredicateクラスも使用されています。アプリケーションでは、weblogic.jdbc.rowset.SQLPredicateクラスを使用することも、独自のフィルタ・クラスを作成することも可能です。詳細については「FilteredRowSetに対するフィルタの設定」を参照してください。

FilteredRowSetの作成

RowSetはファクトリ・インタフェースから作成されます。WebLogic ServerでFilteredRowSetを作成するには、主に以下の手順に従います。

1. RowSetFactoryインスタンスを作成します。このインスタンスはアプリケーションで使用するRowSetオブジェクトを作成するためのファクトリとして機能します。次に例を示します。

RowSetFactory rsfact = RowSetFactory.newInstance();

2. WLCachedRowSetを作成してjavax.sql.rowset.FilteredRowSetオブジェクト型にキャストします。デフォルトではWebLogic newCachedRowSet() RowSetFactoryメソッドでWLCachedRowSetオブジェクトが作成されます。このオブジェクトをそのまま使用することもできますが、標準のFilteredRowSetオブジェクトを使用する場合は、オブジェクトをFilteredRowSetオブジェクトとしてキャストできます。次に例を示します。

FilteredRowSet rs = rsfact.newCachedRowSet();

FilteredRowSetのプロパティの設定

FilteredRowSetのプロパティのオプションはCachedRowSetのオプションと同じです。「CachedRowSetのプロパティの設定」を参照してください。

FilteredRowSetのデータベース接続のオプション

FilteredRowSetのデータベース接続のオプションはCachedRowSetのオプションと同じです。「データベース接続のオプション」を参照してください。

FilteredRowSetへの入力

FilteredRowSetのデータ入力のオプションはCachedRowSetのオプションと同じです。「CachedRowSetへの入力」を参照してください。

FilteredRowSetのメタデータの設定

RowSetのデータ変更をデータベースとの間で同期するために、RowSetにメタデータを設定することが必要な場合もあります。詳細については、「RowSetに対するデータベース更新用メタデータの設定」を参照してください。

FilteredRowSetに対するフィルタの設定

FilteredRowSetの行をフィルタするには、setFilterメソッドを呼び出して、Predicate (フィルタ)オブジェクトをこのメソッドのパラメータとして渡します。Predicateオブジェクトはjavax.sql.rowset.Predicateインタフェースを実装するクラスのインスタンスです。FilteredRowSetのWebLogic実装では、独自のフィルタを定義することも、weblogic.jdbc.rowset.SQLPredicateクラスのインスタンスを使用することもできます。

ユーザー定義のRowSetフィルタ

FilteredRowSet用のフィルタを定義する場合、主に以下の手順に従います。

1. 使用するフィルタ動作(表示する行を特定の列の値を持つ行に制限するなど)を行うjavax.sql.rowset.Predicateインタフェースを実装するクラスを定義します。たとえば、ID列の値の範囲に基づいて表示される行を制限できます。定義するクラスには、ID列の値をフィルタリングするためのロジックが含まれます。

2. クラスのインスタンス(フィルタ)を作成して、使用するフィルタ条件を指定します。たとえば、ID列の値が100から199までの行のみを表示するといった指定が可能です。

3. rowset.setFilter()を呼び出して、クラスをこのメソッドのパラメータとして渡します。

例8-3に、javax.sql.rowset.Predicateインタフェースを実装するクラスのサンプルを示します。このサンプルでは、列の値の大文字と小文字を区別しないバージョンを評価するフィルタを作成することができるクラスが示されます。例8-4に、フィルタ条件を判断するクラスのインスタンスを作成してから、FilteredRowSet用のフィルタとしてフィルタ・オブジェクトを設定するコードを示します。

例 8-3 javax.sql.rowset.Predicateを実装するフィルタ・クラス

package examples.jdbc.rowsets;
import javax.sql.rowset.Predicate;
import javax.sql.rowset.CachedRowSet;
import javax.sql.RowSet;
import java.sql.SQLException;
public class SearchPredicate implements Predicate, java.io.Serializable {
private boolean DEBUG = false;
private String col = null;
private String criteria = null;
//Constructor to create case-insensitive column - value comparison.
public SearchPredicate(String col, String criteria) {
this.col = col;
this.criteria = criteria;
}
public boolean evaluate(RowSet rs)  {
CachedRowSet crs = (CachedRowSet)rs;
boolean bool = false;
try {
debug("evaluate(): "+crs.getString(col).toUpperCase()+" contains "+
criteria.toUpperCase()+" = "+
crs.getString(col).toUpperCase().contains(criteria.toUpperCase()));
if (crs.getString(col).toUpperCase().contains(criteria.toUpperCase()))
bool = true;
} catch(Throwable t) {
t.printStackTrace();
throw new RuntimeException(t.getMessage());
}
return bool;
}
public boolean evaluate(Object o, String s) throws SQLException {
throw new SQLException("String evaluation is not supported.");
}
public boolean evaluate(Object o, int i) throws SQLException {
throw new SQLException("Int evaluation is not supported.");
}
}

例 8-4 FilteredRowSet用のフィルタを設定するコード

SearchPredicate pred = new SearchPredicate(ROWSET_LASTNAME, lastName);
rs.setFilter(pred);

WebLogic SQL方式フィルタ

Weblogic Serverにはjavax.sql.rowset.Predicateインタフェースを実装するweblogic.jdbc.rowset.SQLPredicateクラスが用意されています。SQLPredicateクラスを使用すると、SQLのようなWHERE句の構文を使用するフィルタを定義してRowSetの行をフィルタできます。次に例を示します。

SQLPredicate filter = new SQLPredicate("ID >= 103");
rs.setFilter(filter);

詳細については、「SQLPredicate、SQL方式のRowSetフィルタ」を参照してください。

FilteredRowSetのデータの操作

FilteredRowSetのデータの操作はCachedRowSetのデータの操作とほぼ同様です。ただし、行を挿入したり更新したりする場合には、必ずフィルタ条件の範囲内で変更を行って、操作した行が表示される行の集合に残るようにします。たとえば、RowSetのフィルタでID列の値が105より小さい行のみを表示できる場合、ID列の値が106の行を挿入しようとしたり、IDの値を106に更新しようとしたりすると、操作は失敗してSQLExceptionがスローされます。

データ操作の詳細については、「CachedRowSetのデータの操作」を参照してください。

WebRowSet

WebRowSetは、RowSetをXMLフォーマットで読み書きできるキャッシュされたRowSetです。WebRowSetには以下のような特性があります。

- readXml(java.io.InputStream iStream)メソッドを使用してXMLソースからRowSetに入力します。

- writeXml(java.io.OutputStream oStream)メソッドを使用してデータおよびメタデータをXMLで書き込み、他のアプリケーション・コンポーネントで使用できるように、またはリモート・クライアントに送信できるようにします。

- RowSetの入力やRowSetからの書込みに使用されるXMLコードは、標準WebRowSet XMLスキーマ定義に準拠します。この定義はhttp://java.sun.com/xml/ns/jdbc/webrowset.xsdで入手できます。

詳細は、http://www.oracle.com/technetwork/java/javase/jdbc/index.htmlおよびhttp://download.oracle.com/javase/6/docs/api/javax/sql/rowset/WebRowSet.htmlのjavax.sql.rowset.WebRowSetインタフェースのJavadocを参照してください。

注意:
WebLogic ServerではRowSetについて2つのスキーマがサポートされています。1つは標準WebRowSet用、もう1つはWLCachedRowSet用です。これは、JSR-114の最終仕様より前に実装されたものです。

特有のプログラミング上の考慮事項

- WebLogicのWebRowSet実装では2つのXMLスキーマ(およびAPI)がサポートされます。1つは標準のWebRowSet仕様で(http://java.sun.com/xml/ns/jdbc/webrowset.xsdで入手可能)、もう1つはWLCachedRowSet用です。これは、JSR-114の最終仕様より前に実装されたものです。

- WebLogic Server行セットのみを使用している場合、いずれかのスキーマを使用できます。固有スキーマにはより多くの要素タイプがあります。

- 他のRowSetの実装と対話するには、標準のスキーマを使用する必要があります。

JoinRowSet

JoinRowSetとは、SQL JOINによって単一のRowSetに結合された、多数の接続されていないRowSetオブジェクトです。JoinRowSetには以下のような特性があります。

- JoinRowSetに追加される各RowSetには、JoinRowSetへのRowSetの追加に使用されるaddRowSetメソッドで指定された「一致する」列があることが必要です。次に例を示します。

addRowSet(javax.sql.RowSet[] rowset,java.lang.String[] columnName);

- setJoinTypeメソッドを使用して、結合タイプを設定できます。以下の結合タイプがサポートされています。

CROSS_JOIN
FULL_JOIN
INNER_JOIN
LEFT_OUTER_JOIN
RIGHT_OUTER_JOIN

- これらを使用すると、データベースに接続されていなくてもデータを結合できます。

- JoinRowSetsは読取り専用。JoinRowSetはデータベースのデータを更新するためには使用できません。

- JoinRowSetの一致する列は、Number、Boolean、Date、およびStringの4つのデータ型に制限されています。表8-1に、JoinRowSetの一致する列で使用できるデータ型の詳細について示します。

表8-1一致する列で使用できるデータ型

結合の左側のデータ型

結合の右側で使用できるデータ型

Number

Number

String

Boolean

Boolean

String

Date

Date

String

String

String

Number

Boolean

Date

JoinRowSetの詳細は、javax.sql.rowset.Joinable (http://download.oracle.com/javase/6/docs/api/javax/sql/rowset/Joinable.html)およびJoinRowSetインタフェース(http://download.oracle.com/javase/6/docs/api/javax/sql/rowset/JoinRowSet.html)のJavadocを参照してください。

JDBCRowSet

JDBCRowSetはResultSetオブジェクトのラッパーで、これによって結果セットをJavaBeanコンポーネントとして使用できるようになります。JDBCRowSetは、接続されているRowSetです。これ以外の種類のRowSetはすべて接続されていないRowSetです。

詳細は、javax.sql.rowset.JdbcRowSetインタフェースのJavadoc (http://download.oracle.com/javase/6/docs/api/javax/sql/rowset/JdbcRowSet.html)を参照してください。

SyncResolverを使用したSyncProviderExceptionの処理

acceptChanges()を呼び出してRowSetの変更をデータベースに伝播する場合、WebLogic ServerではRowSetの元のデータ(最後の同期以降のデータ)が、データベースのデータとオプティミスティックな同時実行性ポリシーに基づいて比較されます。データの変更が検出されると、javax.sql.rowset.spi.SyncProviderExceptionがスローされます。デフォルトでは、アプリケーションでは何も行う必要はありませんが、RowSetの変更はデータベースと同期されません。こうした例外を処理してシステムに適した方法でデータ変更を行うように、アプリケーションを設計できます。

注意:
javax.sql.rowset.CachedRowSetsについては、RowSetのすべての行にあるすべての元の値が、対応するデータベースの行と比較されます。weblogic.jdbc.rowset.WLCachedRowSet、または他のWebLogic拡張のRowSetでは、オプティミスティックな同時実行性の設定に基づいてデータが比較されます。詳細については、「オプティミスティックな同時実行性ポリシー」を参照してください。

SyncProviderExceptionを処理する主な手順は次のとおりです。

1. javax.sql.rowset.spi.SyncProviderExceptionを捕捉します。

2. この例外からSyncResolverオブジェクトを取得します。「SyncResolverオブジェクトの取得」を参照してください。

3. nextConflict()または任意の他の移動用メソッドを使用して、競合まで移動します。「SyncResolverオブジェクト内の移動」を参照してください。

4. 適切な値を判断して、setResolvedValue() (RowSetに値を設定するメソッド)で設定します。「RowSetデータの同期の競合に対する解決後の値の設定」を参照してください。

5. 競合している値ごとに、手順3と4を繰り返します。

6. RowSetに対して(SyncResolverではなく) rowset.acceptChanges()を呼び出し、新しい解決後の値を使用してデータベースとの間で変更を同期します。「変更の同期」を参照してください。

SyncResolverおよびSyncProviderExceptionの詳細については、RowSetの仕様またはSyncResolverインタフェースのJavadocを参照してください。

注意:
SyncProviderExceptionの解決を開始する前に、他のどのプロセスもデータを更新することのないようにします。

RowSetデータの同期における競合の種類

表8-2に、RowSetからデータベースにデータの変更を同期する際に起こる、競合状況の種類について示します。

表8-2 RowSetの変更をデータベースに同期する際の競合の種類

RowSetデータの変更の種類

データベース・データの変更の種類

ノート

更新

更新

RowSetとデータベースの同じ行の値が変更されました。SyncResolverのステータスはSyncResolver.UPDATE_ROW_CONFLICT。

場合によりアプリケーションで、この競合を解決するロジックを提供するか、ユーザーに新しいデータを提示することが必要になります。

更新

削除

RowSetの行の値は更新されましたが、データベースではその行が削除されました。SyncResolverのステータスはSyncResolver.UPDATE_ROW_CONFLICT。

場合によりアプリケーションで、行を削除されたままにしておく(データベースの状態のようにする)か、行を元に戻してRowSetからの変更を永続化するかを決定するロジックの提供が必要になります。

- 行を削除されたままにするには、RowSetの行の変更を元に戻します。

- 行を元に戻して変更するには、目的の値を持つ新しい行を挿入します。

データベースで行が削除されている場合、競合している値がないことに注意します。getConflictValue()を呼び出すと、weblogic.jdbc.rowset.RowNotFoundExceptionがスローされます。

削除

更新

RowSetの行は削除されましたが、データベースではその行が更新されました。SyncResolverのステータスはSyncResolver.DELETE_ROW_CONFLICT。

場合によりアプリケーションで、行を削除する(RowSetの状態のようにする)か、行を保持してデータベースでの現在の変更を永続化するかを決定するロジックの提供が必要になります。

この場合、行のすべての値が競合した値になります。行を保持してデータベースの現在の値とするには、setResolvedValueを呼び出して、行の各列に解決後の値を設定してデータベースの現在の値にします。削除するには、syncprovider.deleteRow()を呼び出します。

削除

削除

RowSetで行が削除され、データベースでは別のプロセスでその行が削除されました。SyncresolverのステータスはSyncResolver.DELETE_ROW_CONFLICTです。

SyncProviderExceptionを解決するには、RowSetのその行に対する削除処理を取り消す必要があります。

行のどの列にも、競合している値がない(nullもない)ことに注意します。getConflictValue()を呼び出すと、weblogic.jdbc.rowset.RowNotFoundExceptionがスローされます。

挿入

挿入

RowSetに行が挿入され、データベースにも別の行が挿入された場合、主キーの競合が起こることがあります。その場合SQL例外がスローされます。SyncProviderExceptionはスローされないので、この種類の競合をSyncResolverを使って直接的に処理することはできません。

SyncResolverのサンプル・コード

例8-5に、RowSetとデータベースの間で競合している値をSyncResolverを使って解決する方法についての要約されたサンプルを示します。このサンプルでは、競合のあるSyncResolverの各行について、認識されている名前を持つ列の値をチェックします。このサンプルの詳細については、サンプルの後の節で説明します。

例 8-5 SyncResolverの要約済みサンプル・コード

try {
rs.acceptChanges();
} catch (SyncProviderException spex) {
SyncResolver syncresolver = spex.getSyncResolver();
while (syncresolver.nextConflict())  {
int status = syncresolver.getStatus();
int rownum = syncresolver.getRow();
rs.absolute(rownum);
//check for null in each column
//write out the conflict
//set resolved value to value in the db for this example
//handle exception for deleted row in the database
try {
Object idConflictValue = syncresolver.getConflictValue("ID");
if (idConflictValue != null)  {
System.out.println("ID value in db: " + idConflictValue);
System.out.println("ID value in rowset: " + rs.getInt("ID"));
syncresolver.setResolvedValue("ID", idConflictValue);
System.out.println("Set resolved value to " + idConflictValue);
}
else {
System.out.println("ID: NULL - no conflict");
}
} catch (RowNotFoundException e)  {
System.out.println("An exception was thrown when requesting a ");
System.out.println("value for ID. This row was ");
System.out.println("deleted in the database.");
}
. . .
}
try {
rs.acceptChanges();
} catch (Exception ignore2) {
}
}

SyncResolverオブジェクトの取得

SyncProviderExceptionを処理するために、例外を捕捉してそこからSyncResolverオブジェクトを取得できます。次に例を示します。

try {
rowset.acceptChanges();
} catch (SyncProviderException spex) {
SyncResolver syncresolver = spex.getSyncResolver();
. . .
}

SyncResolverは、SyncResolverインタフェースを実装するRowSetです。SyncResolverオブジェクトには、元のRowSetのすべての行に対応する行が含まれます。競合していない値については、SyncResolverでの値はnullになります。競合している値については、データベースの現在の値が値として格納されます。

SyncResolverオブジェクト内の移動

SyncResolverオブジェクトを使用すると、すべての競合に移動して、競合している各値に適切な値を設定できます。SyncResolverインタフェースにはnextConflict()メソッドとpreviousConflict()メソッドが含まれており、これらを使用してnull以外の競合している値を持つSyncResolver内で、直接次の行に移動できます。SyncResolverオブジェクトはRowSetなので、SyncResolverの任意の行へのカーソル移動には、すべてのRowSet移動用メソッドも使用できます。ただし、nextConflict()メソッドおよびpreviousConflict()メソッドを使用すると、競合している値のない行を簡単にスキップできます。

競合している行にカーソルを移動した後には、各列の値をgetConflictValue()メソッドでチェックして、RowSet内の値と競合しているデータベース内の値を検索してから、それらの値を比較して競合の処理方法を決定する必要があります。値が競合していない行の場合、戻り値としてnullが返されます。行がデータベースでは削除されていた場合、戻り値はなく、例外がスローされます。

注意:
WebLogicのRowSet実装では、データベースの行の任意の値と、RowSetの作成時または最後の同期時にRowSetに読み込まれた値が異なる場合、値の競合が発生します。

RowSetとデータベースの値を比較するコードのサンプルを以下に示します。

syncresolver.nextConflict()
for (int i = 1; i <= colCount; i++) {
if (syncresolver.getConflictValue(i) != null)  {
rsValue = rs.getObject(i);
resolverValue = syncresolver.getConflictValue(i);
. . .
// compare values in the rowset and SyncResolver to determine
// which should be the resolved value (the value to persist)
}
}

RowSetデータの同期の競合に対する解決後の値の設定

データベースに永続化するための適切な値を設定するには、setResolvedValue()を呼び出します。次に例を示します。

syncresolver.setResolvedValue(i, resolvedValue);

setResolvedValue()メソッドでは以下の変更が行われます。

- データベースに永続化するための値を設定します。つまり、RowSetの現在の値を設定します。変更が同期されると、この新しい値がデータベースに永続化されます。

- RowSetのデータの元の値をデータベースの現在の値に変更します。元の値とは、最後の同期以降に設定されていた値です。setResolvedValue()を呼び出すと、元の値がデータベースの現在の値になります。

- 同期の呼出しにおけるWHERE句を、データベースの適切な行が更新されるように変更します。

変更の同期

SyncResolverで競合している値を解決した後には、変更をデータベースとの間で同期する必要があります。これを行うには、rowset.acceptChanges()をもう一度呼び出します。acceptChanges()呼出しではSyncResolverオブジェクトがクローズされ、同期の完了後にデータベースのロックが解放されます。

WLCachedRowSet

WLCachedRowSetはCachedRowSets、FilteredRowSets、WebRowSets、およびSortedRowSetsの拡張です。WLCachedRowSetには以下のような特性があります。

- WebLogic ServerのRowSet実装では、すべてのRowSetが元はWLCachedRowsetとして作成されます。WLCachedRowSetは、それを拡張するあらゆる標準RowSet型として互換的に使用できます。

- WLCachedRowSetには、RowSetをより簡単に扱えるようにする便利なメソッド群があり、またオプティミスティックな同時実行性オプションとデータ同期化オプションを設定するメソッド群も含まれています。

- SQLXMLデータ型オブジェクトを読み取ったり更新したりすることはできない場合があります。JDBC 4.0仕様では、ベンダーがSQLXMLオブジェクトを設定後にこれを読取り可能にする必要はないとしています。WebLogic ServerがSQLXMLデータ型オブジェクトに値を設定したら、このオブジェクトを読み取ったり更新したりできなくなります。

詳細については、weblogic.jdbc.rowset.WLCachedRowSetインタフェースのJavadocを参照してください。

SharedRowSet

RowSetは1つのスレッドでのみ使用できます。複数のスレッドで共有することはできません。SharedRowSetはCachedRowSetを拡張したもので、元のCachedRowSetのデータに基づいて、他のスレッドで使用するCachedRowSetを追加作成できます。SharedRowSetには以下のような特性があります。

- 各SharedRowSetは、元のRowSetの表層的なコピー(データのコピーではなく、元のRowSetのデータへの参照)で、独自のコンテキスト(カーソル、フィルタ、ソーター、保留中の変更、および同期プロバイダ)を備えています。

- 任意のSharedRowSetで行われたデータの変更がデータベースとの間で同期されると、基底のCachedRowSetも更新されます。

- SharedRowSetを使用すると、アプリケーションで必要とするデータベースへの往復回数が減るため、パフォーマンスが向上する可能性があります。

SharedRowSetを作成するには、WLCachedRowSetインタフェースのcreateShared()メソッドを使用して、その結果をWLCachedRowSet型にキャストします。次に例を示します。

WLCachedRowSet sharedrowset = (WLCachedRowSet)rowset.createShared();

SortedRowSet

SortedRowSetはCachedRowSetを拡張して、CachedRowSetの行をアプリケーションで提供されるComparatorオブジェクトに基づいてソートできるようにしたものです。SortedRowSetには以下のような特性があります。

- ソート処理の設定方法は、FilteredRowSetでのフィルタ処理の設定方法と同様。ただし、ソート処理はjavax.sql.rowset.Predicateオブジェクトではなくjava.util.Comparatorオブジェクトに基づきます。

1. アプリケーションで、目的のソート動作を行うComparatorオブジェクトを作成します。

2. 続いてアプリケーションでsetSorter(java.util.Comparator)メソッドを使用してソート条件を設定します。

- ソート処理はメモリー内で行われ、データベース管理システムには依存しません。SortedRowSetを使用することによりデータベースへの往復回数が減るため、アプリケーションのパフォーマンスが向上する可能性があります。

- WebLogic Serverにはjava.util.Comparatorを実装するSQLComparatorオブジェクトが用意されています。これを使用して、ソート条件として使う列のリストを渡すことで、SortedRowSetの行をソートできます。次に例を示します。

rs.setSorter(new weblogic.jdbc.rowset.SQLComparator("columnA,columnB,columnC"));

詳細については、Javadocsで以下について参照してください。

- weblogic.jdbc.rowset.SortedRowSetインタフェース

- weblogic.jdbc.rowset.SQLComparatorクラス

SQLPredicate、SQL方式のRowSetフィルタ

ここでは、SQLPredicateクラスについて説明します。

SQLPredicateとは

Weblogic Serverにはjavax.sql.rowset.Predicateインタフェースの実装であるweblogic.jdbc.rowset.SQLPredicateクラスが用意されています。SQLPredicateクラスを使用すると、SQLのようなWHERE句の構文を使用してFilteredRowSetのフィルタを定義できます。

SQLPredicateの文法

SQLPredicateクラスの文法はJMSセレクタの文法から借用されたもので、SQL SELECT文のWHERE句の文法とよく似ています。

重要な注意事項を以下に示します。

- 列を参照する場合、列名を使用する必要があります。列の索引番号は使用できません。

- この文法では、演算子および数学演算がサポートされます。たとえば次のようなことができます。

(colA + ColB) >=100.

- WHERE句の作成では、単純なデータ型のみを使用できます。以下のようなデータ型を使用できます。

- String

- Int

- Boolean

- Float

- 以下のような複合データ型はサポートされません。

- Array

- BLOB

- CLOB

- Date

サンプル・コード

//S E T   F I L T E R
//use SQLPredicate class to create a SQLPredicate object,
//then pass the object in the setFilter method to filter the RowSet.
SQLPredicate filter = new SQLPredicate("ID >= 103");
rs.setFilter(filter);

詳細については、weblogic.jdbc.rowset.SQLPredicateクラスのJavadocを参照してください。

オプティミスティックな同時実行性ポリシー

ほとんどの場合、RowSetへのデータの入力とデータベースの更新は別々のトランザクションで発生します。データベース内の基底のデータは2つのトランザクションの間に変更される可能性があります。WebLogic ServerのRowSet実装(WLCachedRowSet)では、オプティミスティックな同時実行性制御を使用して、データベースの一貫性を確保します。

オプティミスティックな同時実行性の場合、RowSetは複数のユーザーが同じデータを同時に変更する可能性は低いという前提で動作します。そのため、接続されていないRowSetモデルの一端として、RowSetではデータベース・リソースがロックされません。ただし、データベースに変更を書き込む前に、データベース内の変更予定のデータが、そのデータがRowSetに読み込まれたときから変更されていないことをRowSetでチェックする必要があります。

RowSetから発行されるUPDATE文とDELETE文には、データベース内のデータを、RowSetの入力時に読み込まれたデータに照らして検証するためのWHERE句が含まれます。RowSetではデータベース内の基底のデータが変更されたことが検出されるとOptimisticConflictExceptionが発行されます。アプリケーションではこの例外を捕捉して処理方法を決定できます。一般的には、アプリケーションで、変更されたデータをリフレッシュしてユーザーに再度提示します。

WLCachedRowSet実装には複数のオプティミスティックな同時実行性ポリシーが用意されています。これらのポリシーによって、基底のデータベースのデータを検証するためにRowSetから発行されるSQLが決まります。

- VERIFY_READ_COLUMNS

- VERIFY_MODIFIED_COLUMNS

- VERIFY_SELECTED_COLUMNS

- VERIFY_NONE

- VERIFY_AUTO_VERSION_COLUMNS

- VERIFY_VERSION_COLUMNS

これらのポリシーの違いを例示するために、以下のような内容の例を使用します。

- 3つの列がある簡単な従業員表

CREATE TABLE employees (
e_id integer primary key,
e_salary integer,
e_name varchar(25)
);

- 表内の1つの行

e_id = 1, e_salary = 10000, and e_name = 'John Smith'

以下に示すオプティミスティックな同時実行性ポリシーのそれぞれの例では、RowSetに従業員表からこの行が読み込まれ、John Smithの給与が20000に設定されます。続いて、オプティミスティックな同時実行性ポリシーがRowSetから発行されるSQLコードにどのように影響するかが示されます。

VERIFY_READ_COLUMNS

デフォルトでは、RowSetのオプティミスティックな同時実行性制御ポリシーはVERIFY_READ_COLUMNSです。RowSetからUPDATEまたはDELETEが発行されるときに、データベースから読み込まれたすべての列がWHERE句に含まれます。これによって、RowSetに最初に読み込まれたすべての列の値について変更されてないかどうかが検証されます。

この例では、RowSetから次のように発行されます。

UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_salary=10000 AND e_name = 'John Smith';

VERIFY_MODIFIED_COLUMNS

VERIFY_MODIFIED_COLUMNSポリシーでは、主キー列と更新される列のみがWHERE句に含まれます。アプリケーションで更新される列の一貫性だけを考慮する場合に便利です。データを読み込んだ後に更新の対象外の列が変更されていても、この更新をコミットできます。

この例では、RowSetから次のように発行されます。

UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_salary=10000

e_id列は主キー列なので含まれています。e_salary列は更新される列なので、同様に含まれています。e_name列は読み込まれただけなので、検証されません。

VERIFY_SELECTED_COLUMNS

VERIFY_SELECTED_COLUMNSでは、主キー列と指定する列がWHERE句に含まれます。

WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
metaData.setOptimisticPolicy(WLRowSetMetaData.VERIFY_SELECTED_COLUMNS);
// Only verify the e_salary column
metaData.setVerifySelectedColumn("e_salary", true);

metaData.acceptChanges();

この例では、RowSetから次のように発行されます。

UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_salary=10000

e_id列は主キー列なので含まれています。e_salary列は選択された列なので、同様に含まれています。

VERIFY_NONE

VERIFY_NONEポリシーでは、主キー列のみがWHERE句に含まれます。データベース・データに対して追加で検証は行われません。

この例では、RowSetから次のように発行されます。

UPDATE employees SET e_salary = 20000 WHERE e_id = 1

VERIFY_AUTO_VERSION_COLUMNS

VERIFY_AUTO_VERSION_COLUMNSでは、主キー列と、別個のバージョン列がWHERE句に含まれます。RowSetでは更新の一環としてバージョン列の自動的なインクリメントも行われます。このバージョン列のデータ型はintegerでなければなりません。データベース・スキーマを更新して、別個のバージョン列(e_version)を含める必要があります。例では、この列の現在の値が1であると仮定します。

metaData.setOptimisticPolicy(WLRowSetMetaData.
VERIFY_AUTO_VERSION_COLUMNS);

metaData.setAutoVersionColumn("e_version", true);

metaData.acceptChanges();

この例では、RowSetから次のように発行されます。

UPDATE employees SET e_salary = 20000, e_version = 2
WHERE e_id = 1 AND e_version = 1

e_version列はSET句で自動的にインクリメントされます。WHERE句は主キー列とバージョン列を検証しています。

VERIFY_VERSION_COLUMNS

VERIFY_VERSION_COLUMNSの場合、RowSetでは主キー列と、別個のバージョン列がチェックされます。RowSetでは更新の一環としてバージョン列はインクリメントされません。データベース・スキーマを更新して、別個のバージョン列(e_version)を含める必要があります。例では、この列の現在の値が1であると仮定します。

metaData.setOptimisticPolicy(WLRowSetMetaData.VERIFY_VERSION_COLUMNS);
metaData.setVersionColumn("e_version", true);
metaData.acceptChanges();

この例では、RowSetから次のように発行されます。

UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_version = 1

WHERE句では主キー列とバージョン列が検証されます。RowSetでバージョン列がインクリメントされないため、この処理はデータベースで行う必要があります。一部のデータベースでは、行の更新時に自動的にインクリメントするバージョン列を提供しています。データベース・トリガーを使用してこのタイプの更新を処理することもできます。

オプティミスティックな同時実行性制御の制限

オプティミスティックなポリシーでは、変更する行に対するUPDATE文とDELETE文のみが検証されます。読取り専用の行はデータベースに照らして検証されません。

ほとんどのデータベースではWHERE句でのBLOBまたはCLOB列の使用が許可されていないため、RowSetではBLOBまたはCLOB列の検証はできません。

RowSetに複数の表が含まれる場合、RowSetでは更新された表のみが検証されます。

オプティミスティックなポリシーの選択

デフォルトのVERIFY_READ_COLUMNSでは、パフォーマンスを多少犠牲にして、強力なレベルの一貫性が提供されます。最初に読み込まれたすべての列をデータベースに送信したり、データベースと比較したりする必要があるため、このポリシーでは多少のオーバーヘッドが追加で発生します。VERIFY_READ_COLUMNSは強力なレベルの一貫性が必要な場合に適しています。バージョン列を含めるようにデータベース表を変更することはできません。

VERIFY_SELECTED_COLUMNSは、開発者が検証を完全に制御する必要があり、アプリケーションに固有の知識を使用してSQLを微調整する場合に便利です。

VERIFY_AUTO_VERSION_COLUMNSでは、VERIFY_READ_COLUMNSと同じレベルの一貫性が提供されますが、integer型の1つの列を比較するだけで済みます。このポリシーではバージョン列のインクリメントも行われるため、データベースの設定が若干必要です。

VERIFY_VERSION_COLUMNSは、最高レベルのパフォーマンスと一貫性が必要な本番システムにお薦めします。VERIFY_AUTO_VERSION_COLUMNSと同様に、高いレベルの一貫性が提供されますが、データベースで1つの列の比較が行われるだけです。VERIFY_VERSION_COLUMNSでは、データベースでバージョン列のインクリメントを行う必要があります。一部のデータベースでは、更新時に自動的にインクリメントする列タイプを提供していますが、この動作はデータベース・トリガーを使用して実装することもできます。

VERIFY_MODIFIED_COLUMNSとVERIFY_NONEでは一貫性が確保される程度は低下しますが、オプティミスティックな競合が起きる可能性も少なくなります。高レベルなデータの一貫性の必要性よりも、パフォーマンス、競合の回避の方が重要な場合は、これらのポリシーを検討します。

パフォーマンスのオプション

RowSetを使用する場合は以下のパフォーマンス・オプションを検討します。

JDBCのバッチ処理

RowSet実装ではJDBCのバッチ処理もサポートされています。各SQL文をJDBCドライバに個々に送信する代わりに、バッチ処理では文の集合を1つの一括処理としてJDBCドライバに送信します。バッチ処理はデフォルトで無効になっていますが、一般に1つのトランザクションで多数の更新が発生する場合にパフォーマンスが向上します。アプリケーションとデータベースに対してこのオプションを有効および無効に設定して、ベンチマークを実行してみるとよいでしょう。

WLCachedRowSetインタフェースには、INSERT、DELETE、およびUPDATE文のバッチ処理を制御するためのsetBatchInserts(boolean)、setBatchDeletes(boolean)、およびsetBatchUpdates(boolean)メソッドがあります。

注意:
setBatchInserts、setBatchDeletes、setBatchUpdatesメソッドは、acceptChangesメソッドを呼び出す前に呼び出す必要があります。

Oracle Databaseのバッチ処理の制限

WLCachedRowSetはオプティミスティックな同時実行性制御に依存しているため、更新または削除コマンドが成功したか、オプティミスティックな競合が発生したかを判別する必要があります。WLCachedRowSet実装では、文によって更新された行の数についてのJDBCドライバの報告に基づいて、競合が発生したかどうかを判別します。更新された行が0の場合、WLCachedRowSetでは競合が発生したと認識されます。

Oracle JDBCドライバではバッチ更新が実行されるとjava.sql.Statement.SUCCESS_NO_INFOが返されるため、RowSet実装では競合が発生したかどうかを判別するために戻り値を使用できません。

バッチ処理がOracleデータベースで使用されることがRowSetで検出された場合、バッチ処理の動作は自動的に変更されます。

バッチ挿入は検証されないため、通常どおり実行されます。

バッチ更新は正常に実行されますが、RowSetでは特別なSELECT問合せが発行され、バッチ更新でオプティミスティックな競合が発生したかどうかがチェックされます。

SELECT検証問合せの後でバッチ削除を実行するよりも効率的なため、バッチ削除ではグループ削除が使用されます。

グループ削除

複数の行を削除する場合、RowSetでは通常、削除する行ごとにDELETE文が発行されます。グループ削除を有効にした場合、RowSetでは削除する行を含むWHERE句が指定されたDELETE文が1つだけ発行されます。

たとえば、表から3人の従業員を削除する場合、通常であればRowSetから次のように発行されます。

DELETE FROM employees WHERE e_id = 3 AND e_version = 1;
DELETE FROM employees WHERE e_id = 4 AND e_version = 3;
DELETE FROM employees WHERE e_id = 5 AND e_version = 10;

グループ削除を有効にした場合、RowSetから次のように発行されます。

DELETE FROM employees
WHERE e_id = 3 AND e_version = 1 OR
e_id = 4 AND e_version = 3 OR
e_id = 5 AND e_version = 10;

WLRowSetMetaData.setGroupDeleteSizeを使用すると、1つのDELETE文に含まれる行の数を決定できます。デフォルト値は50です。

9 JDBCのトラブルシューティング

この章では、JDBCアプリケーションの開発時によくある問題について説明します。

- UNIXでのOracle Database関連の問題

- UNIXでのスレッド関連の問題

- JDBCオブジェクトのクローズ

- Microsoft SQL Serverでのネストされたトリガーの使用

UNIXでのOracle Database関連の問題

使用するスレッディング・モデルを確認してください。Oracleドライバを使用する場合は、ネイティブ・スレッドを使用することをお薦めします。ネイティブ・スレッドの使用を指定するには、Javaを起動するときに-nativeフラグを追加します。

UNIXでのスレッド関連の問題

UNIXでは、グリーン・スレッドとネイティブ・スレッドという2つのスレッディング・モデルを利用できます。詳細は、http://www.oracle.com/technetwork/java/index.htmlでSolarisオペレーティング環境用JDKに関する情報を参照してください。

使用しているスレッドの種類は、THREADS_TYPE環境変数を調べることで確認できます。この変数が設定されていない場合は、Javaのbinディレクトリにあるシェル・スクリプトを調べてください。

一部の問題は、各オペレーティング・システムのJVMでのスレッドの実装に関連しています。すべてのJVMで、オペレーティング・システム固有のスレッドの問題が等しく適切に処理されるわけではありません。以下に、スレッド関連の問題を防止するためのヒントを紹介します。

- Oracleドライバを使用する場合は、ネイティブ・スレッドを使用します。

- HP UNIXを使用する場合は、バージョン11.xにアップグレードします。HP UX 10.20などの旧バージョンではJVMとの互換性に問題があります。

- HP UNIXの場合、新しいJDKではグリーン・スレッド・ライブラリがSHLIB_PATHに追加されません。現在のJDKでは、SHLIB_PATHで定義されたパスにある場合を除いて、共有ライブラリ(.sl)を見つけられません。SHLIB_PATHの現在の値を確認するには、コマンド・ラインで次のように入力します。

$ echo $SHLIB_PATH

setコマンドまたはsetenvコマンドを使用すると(どちらを使用するかはシェルによる)、シンボルSHLIB_PATHで定義されたパスにWebLogicの共有ライブラリを追加できます。SHLIB_PATHで定義されていない場所にある共有ライブラリが認識されるようにするには、使用するシステムの管理者に連絡する必要があります。

JDBCオブジェクトのクローズ

プログラムが効率的に実行されるように、Connection、Statement、ResultSetなどのJDBCオブジェクトは必ずfinallyブロックでクローズすることをお薦めします。次に、一般的な例を示します。

例 9-1 JDBCオブジェクトのクローズ

try {

Driver d =
(Driver)Class.forName("oracle.jdbc.OracleDriver").newInstance();

Connection conn = d.connect("jdbc:weblogic:oracle:myserver",
"scott", "tiger");

Statement stmt = conn.createStatement();
stmt.execute("select * from emp");
ResultSet rs = stmt.getResultSet();
// do work

}

catch (Exception e) {

// handle any exceptions as appropriate

}

finally {

try {rs.close();}
catch (Exception rse) {}
try {stmt.close();}
catch (Exception sse) {}
try {conn.close();
catch (Exception cse) {}

}

JDBCオブジェクトの破棄

また、次のような処理も行わないでください。破棄されたJDBCオブジェクトが作成されます。

//Do not do this.
stmt.executeQuery();
rs = stmt.getResultSet();

//Do this instead
rs = stmt.executeQuery();

上記の例の最初の行では、破棄されており、すぐにガベージ・コレクションが行われる可能性のある結果セットが作成されます。

Microsoft SQL Serverでのネストされたトリガーの使用

以下の節では、Microsoft SQL Serverデータベースでネストされたトリガーを使用する場合のトラブルシューティング情報を示します。

- ネスト・レベルの超過

- トリガーとEJBの使用

サポートされるデータベースとデータベース・ドライバの情報については、「Oracle Fusion Middleware Supported System Configurations」ページ(http://www.oracle.com/technetwork/middleware/ias/downloads/fusion-certification-100350.html)を参照してください。

ネスト・レベルの超過

SQL Serverデータベースでネスト・レベルが超過したことを示すSQL Serverエラーが発生する場合があります。

次に例を示します。

CREATE TABLE EmployeeEJBTable (name varchar(50) not null,salary int, card
varchar(50), primary key (name))

CREATE TABLE CardEJBTable (cardno varchar(50) not null, employee
varchar(50), primary key (cardno), foreign key (employee) references
EmployeeEJB Table(name) on delete cascade)
CREATE TRIGGER  card on EmployeeEJBTable for delete as delete    CardEJBTable
where employee in (select name from deleted)

CREATE TRIGGER  emp on CardEJBTable for delete as delete EmployeeEJBTable
where card in (select cardno from deleted)

insert into EmployeeEJBTable values ('1',1000,'1')
insert into CardEJBTable values ('1','1')
DELETE FROM CardEJBTable WHERE cardno = 1

以下のようなエラー・メッセージになります。

Maximum stored procedure, function, trigger, or view nesting level exceeded  (limit 32).

この問題を回避するには、次のようにします。

1. 以下のスクリプトを実行して、ネストされたトリガーのレベルを0にリセットします。

-- Start batch
exec sp_configure 'nested triggers', 0  -- This set's the new value.
reconfigure with override -- This makes the change permanent
-- End batch

2. 以下のスクリプトを実行して、SQL Serverの現在の値を確認します。

exec sp_configure 'nested triggers'

トリガーとEJBの使用

EJBとMicrosoftドライバを使用するアプリケーションで、execute()メソッドからの戻りコードが0、予期していた値が1 (1レコード削除)という状況が発生する場合があります。

次に例を示します。

CREATE TABLE EmployeeEJBTable (name varchar(50) not null,salary int, card
varchar(50), primary key (name))

CREATE TABLE CardEJBTable (cardno varchar(50) not null, employee
varchar(50), primary key (cardno), foreign key (employee) references
EmployeeEJB Table(name) on delete cascade)
CREATE TRIGGER  emp on CardEJBTable for delete as delete EmployeeEJBTable
where card in (select cardno from deleted)

insert into EmployeeEJBTable values ('1',1000,'1')
insert into CardEJBTable values ('1','1')
DELETE FROM CardEJBTable WHERE cardno = 1
The EJB code assumes that the record is not found and throws an appropriate error
message.
To work around this issue, run the following script:
exec sp_configure 'show advanced options', 1
reconfigure with override
exec sp_configure 'disallow results from triggers',1
reconfigure with override

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