ヘッダーをスキップ
Oracle Database JDBC開発者ガイド
11gリリース2(11.2)
B56281-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

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

この付録では、Java Database Connectivity(JDBC)アプリケーションまたはアプレットのトラブルシューティングについて説明します。内容は次のとおりです。

一般的な問題

この項では、Oracle JDBCドライバの使用中に発生する可能性のある、一般的な問題について説明します。たとえば、次の問題があります。

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

PL/SQLでは、CHARまたはVARCHAR2列がOUTまたはIN/OUT変数として定義される場合、ドライバは32512文字のCHAR配列を割り当てます。このため、メモリー消費に関する問題が生じます。JDBC Thinドライバは、VARCHAR2出力型を使用する場合、メモリーを割り当てません。ただし、JDBC OCIドライバは、CHARVARCHAR2の両方の型に対してメモリーを割り当てます。このため、OCIドライバのCPU負荷はThinドライバより高くなります。

以前のリリースでは、この問題はStatement.setMaxFieldSizeメソッドをコールすることで解決できました。これよりもよい解決方法は、OracleCallableStatement.registerOutParameterを使用することです。すべてのCHARまたはVARCHAR2列で、必ずregisterOutParameter(int paramIndex, int sqlType, int scale, int maxLength)をコールすることをお薦めします。このメソッドは、oracle.jdbc.driver.OracleCallableStatementに定義されています。4つ目の引数maxLengthを使用して、メモリー消費を制限します。このパラメータは、この列の格納に必要な文字数をドライバに指示します。文字配列に列データを保持できない場合、列は切り捨てられます。3つ目の引数scaleは、ドライバでは無視されます。

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

カーソルまたはメモリーが不足しているというメッセージを受け取った場合は、すべてのStatementおよびResultSetオブジェクトを明示的にクローズしてください。Oracle JDBCドライバには、ファイナライザ・メソッドがありません。クリーン・アップ・ルーチンは、ResultSetおよびStatementクラスのcloseメソッドで実行されます。結果セットおよび文オブジェクトを明示的にクローズしておかないと、重大なメモリー・リークが発生します。また、データベースのカーソルが不足します。文をクローズすると、データベース内の対応するカーソルが解放されます。

同様に、サーバー側でのリークおよびカーソル不足を避けるには、Connectionオブジェクトも明示的にクローズしておく必要があります。接続をクローズすると、その接続に関連付けられたオープン中の文オブジェクトが、JDBCドライバによってクローズされ、サーバー側のカーソルが解放されます。

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

JDBCドライバでは、PL/SQLストアド・プロシージャにBOOLEANパラメータを渡せません。PL/SQLプロシージャにBOOLEAN値が含まれている場合、そのPL/SQLプロシージャを、引数をINTとして受け取る2番目のPL/SQLプロシージャでラップし、最初のストアド・プロシージャに渡します。2番目のプロシージャがコールされると、サーバーによってINTからBOOLEANに変換されます。

ストアド・プロシージャの例を示します。BOOLPROCは、BOOLEANパラメータを渡そうとします。2番目のプロシージャBOOLWRAPは、BOOLEAN値とINT値の置換えを実行します。

CREATE OR REPLACE PROCEDURE boolproc(x boolean)
AS
BEGIN
[...]
END;

CREATE OR REPLACE PROCEDURE boolwrap(x int)
AS
BEGIN
IF (x=1) THEN
  boolproc(TRUE);
ELSE
  boolproc(FALSE);
END IF;
END;

// Create the database connection from a DataSource
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@<...hoststring...>");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
CallableStatement cs = conn.prepareCall ("begin boolwrap(?); end;");
cs.setInt(1, 1);
cs.execute ();

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

必ずしも1プロセスで約17以上のJDBC-OCI接続をオープンできないことがあります。サーバー上のプロセス数が初期化ファイルに指定されている制限を超えたためか、またはプロセスごとのファイル記述子の制限を超えた可能性があります。1つのJDBC-OCI接続で、複数のファイル記述子が使用される(3から4個のファイル記述子が使用されます)ことがあります。

サーバーで17以上のプロセスを使用可能にしている場合は、プロセスごとのファイル記述子の制限が原因である可能性があります。この制限数を増やすと、解決する可能性があります。

Statement.cancelの使用

JDBC標準メソッドStatement.cancelは、データベースにメッセージを送信することにより、SQL文の実行を正常に停止させます。データベースは、これに応答して実行を停止し、エラー・メッセージを返します。Statement.executeをコールしたJavaスレッドはサーバーで待機し、他のスレッドからのStatement.cancelコールにより呼び出された返答のエラー・メッセージを受信した場合にのみ実行を続けます。

このため、Statement.cancelは、ネットワークとデータベースが正しく機能していることに依存します。ネットワーク接続が切断するか、データベース・サーバーがダウンした場合、クライアントは取消しメッセージに対するエラー応答を受け取りません。サーバー・プロセスに障害が発生すると、多くの場合、JDBCはStatement.executeをコールしたスレッドを解放するIOExceptionを受け取ります。ただし、サーバーがダウンしてもJDBCがIOExceptionを受け取らない場合があります。Statement.executeを開始したスレッドは、Statement.cancelによって解放されません。

JDBCがIOExceptionを受け取らない場合は、Oracle Netがいずれはタイムアウトし、接続をクローズすることになります。これにより、IOExceptionが発生し、スレッドが解放されます。ただし、このプロセスにはかなりの時間がかかることがあります。このタイムアウトを制御する方法は、OracleDatasource.setConnectionProperties()readTimeoutプロパティの説明を参照してください。このタイムアウトは、Oracle Netの設定を使用してチューニングすることもできます。詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。

JDBC標準メソッドStatement.setQueryTimeoutは、Statement.cancelに依存します。指定されたタイムアウト間隔よりも実行時間が長くなった場合、モニター・スレッドがStatement.cancelをコールします。これは、前述と同じすべての制限を受けます。この結果、Statement.executeをコールしたスレッドがタイムアウトにより解放されない場合があります。

実行と取消しの間の時間の長さは、それほど正確ではありません。この間隔は、指定されたタイムアウト間隔より短くはなりませんが、数秒間長くなることがあります。アプリケーションに、高い優先順位で実行されているアクティブ・スレッドがある場合、この間隔は随意に長くなることがあります。モニター・スレッドは高い優先順位で実行されますが、他にも高い優先順位のスレッドがあり、それが実行し続けられる場合があります。モニター・スレッドが開始されるのは、ゼロ以外のタイムアウトで実行される文がある場合のみです。すべてのOracle JDBC文の実行を監視するモニター・スレッドは、1つのみあります。

Statement.cancelStatement.setQueryTimeoutは、サーバー側内部ドライバでサポートされません。サーバー側内部ドライバは単一スレッドのサーバー・プロセスで動作します。Oracle JVMはこの単一スレッド・プロセス内にJavaスレッドを実装します。サーバー側内部ドライバがSQL文を実行している場合、JavaスレッドはStatement.cancelをコールできません。これは、Oracle JDBC監視スレッドにも適用されます。

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

アイドル接続に対するファイアウォール・タイムアウトによって、接続が切断される場合があります。このために、JDBCアプリケーションが接続の待機中に停止する可能性があります。ファイアウォール・タイムアウトによって接続が切断されないようにするには、次の処理を1つ以上実行します。

  • 接続キャッシュまたは接続プーリングを使用している場合は、接続キャッシュのInactivityタイムアウト値を、常にファイアウォールのアイドル・タイムアウト値より短い値に設定します。

  • 接続プロパティとしてoracle.net.READ_TIMEOUTを渡してソケット上で読込みタイムアウトを有効にします。タイムアウト値はミリ秒で指定します。

  • JDBC OCIドライバとJDBC Thinドライバの両方について、ネット記述子を使用してデータベースに接続し、接続記述子のDESCRIPTION句にENABLE=BROKENパラメータを指定します。また、TCP_KEEPALIVE_INTERVALの下限値も設定します。

  • サーバー側のsqlnet.oraファイルにSQLNET.EXPIRE_TIME=1を設定して、Oracle Net DCDを使用可能にします。

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

ネットワークの信頼性が低い場合、サーバーの接続が突然切断されても、クライアントでは頻繁に発生する切断を検出するのが困難です。デフォルトでは、Linux上で稼働するクライアントは、突然の切断を検出するのに7200秒(2時間)かかります。この値は、tcp_keepalive_timeプロパティの値と同じです。アプリケーションが切断をより迅速に検出するようにするには、tcp_keepalive_timetcp_keepalive_intervalおよびtcp_keepalive_probesプロパティの値をオペレーティング・システム・レベルでより小さい値に設定する必要があります。


注意:

tcp_keepalive_intervalプロパティに小さい値を設定すると、ネットワーク上にプローブ・パケットが頻繁に送出され、システム速度が低下する可能性があります。そのため、このプロパティの値は、システム要件に基づいて適切に設定してください。

また、接続記述子のDESCRIPTION句にENABLE=BROKENパラメータを指定する必要があります。たとえば、次のようになります。

jdbc:oracle:thin:@(DESCRIPTION=(ENABLE=BROKEN)(ADDRESS=(PROTOCOL=tcp)(PORT=1521)(HOST=myhost))(CONNECT_DATA=(SID=orcl)))

基本的なデバッグ処理

JDBCプログラムのデバッグ方法について説明します。

デバッグに役立つスタック・トレースの出力など、SQL例外の処理については、「SQL例外の処理」を参照してください。

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

クライアントおよびサーバーのOracle-Netトレースが、Oracle Net経由で送信されるパケットをトラップできるようにできます。クライアント側トレースはJDBC OCIドライバについてのみ使用できます。JDBC Thinドライバについてはサポートされません。トレースとトレース・ファイルの読取りに関する詳細な情報は、Oracle Net Services管理者ガイドを参照してください。

トレース機能を使用すると、ネットワーク・イベントが実行されるたびにそのイベントについて記述される、一連の詳細な文が生成されます。操作をトレースすることにより、イベントの内部操作に関する詳細な情報を取り出すことができます。この情報は読込み可能ファイルに出力され、エラーの原因となったイベントを特定できます。トレース情報の収集は、SQLNET.ORAファイルにあるいくつかのOracle Netパラメータによって制御されます。SQLNET.ORAのパラメータを設定した後に、トレースを実行するために新しい接続を作成する必要があります。

トレース・レベルを高くすると、より詳細な情報がトレース・ファイルに取得されます。トレース・ファイルの理解が難しくなるため、トレースを有効にする場合はトレース・レベル4から開始します。トレース・ファイルの最初の部分は接続ハンドシェイク情報です。JDBCプログラムに関連するSQL文とエラー・メッセージの情報は、その先を参照してください。


注意:

トレース機能ではディスク領域が大量に使用されるため、システムのパフォーマンスが大幅に低下する可能性があります。トレースは、必要なときにのみ使用可能にしてください。

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

クライアント・システムのSQLNET.ORAファイルに、次のパラメータを設定します。

TRACE_LEVEL_CLIENT

目的

トレースを一定の指定レベルでオン/オフにします。

デフォルト値

0またはOFF

有効な値

  • 0またはOFF- トレースの出力なし

  • 4またはUSER- ユーザー・トレース情報

  • 10またはADMIN- 管理トレース情報

  • 16またはSUPPORT- カスタマ・サポート・トレース情報

例:

TRACE_LEVEL_CLIENT=10

TRACE_DIRECTORY_CLIENT

目的

トレース・ファイルの書込み先ディレクトリを指定します。

デフォルト値

ORACLE_HOME/network/trace

例:

UNIX: TRACE_DIRECTORY_CLIENT=/oracle/traces

Windows: TRACE_DIRECTORY_CLIENT=C:\ORACLE\TRACES

TRACE_FILE_CLIENT

目的

クライアント・トレース・ファイルの名前を指定します。

デフォルト値

SQLNET.TRC

例:

TRACE_FILE_CLIENT=cli_Connection1.trc


注意:

TRACE_FILE_CLIENTファイルのために選択する名前は、TRACE_FILE_SERVERファイルのために選択する名前と異なっている必要があります。

TRACE_UNIQUE_CLIENT

目的

クライアント側の各トレースに一意の名前を付け、各トレース・ファイルが次に発生したクライアント・トレースによって上書きされないようにします。ファイル名の最後にPIDが付加されます。

デフォルト値

OFF

例:

TRACE_UNIQUE_CLIENT = ON

サーバー側のトレース

サーバー・システムのSQLNET.ORAファイルに次のパラメータを設定します。接続ごとに、一意のファイル名を持つ個別のファイルが生成されます。

TRACE_LEVEL_SERVER

目的

トレースを一定の指定レベルでオン/オフにします。

デフォルト値

0またはOFF

有効な値

  • 0またはOFF- トレースの出力なし

  • 4またはUSER- ユーザー・トレース情報

  • 10またはADMIN- 管理トレース情報

  • 16またはSUPPORT- カスタマ・サポート・トレース情報

例:

TRACE_LEVEL_SERVER=10

TRACE_DIRECTORY_SERVER

目的

トレース・ファイルの書込み先ディレクトリを指定します。

デフォルト値

ORACLE_HOME/network/trace

例:

TRACE_DIRECTORY_SERVER=/oracle/traces

TRACE_FILE_SERVER

目的

サーバー・トレース・ファイルの名前を指定します。

デフォルト値

SERVER.TRC

例:

TRACE_FILE_SERVER= svr_Connection1.trc


注意:

TRACE_FILE_SERVERファイルのために選択する名前は、TRACE_FILE_CLIENTファイルのために選択する名前と異なっている必要があります。

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

Intersolv社のJDBCSpyおよびJDBCTestなどのツールを使用して、JDBC APIレベルで問題に対処できます。これらのツールは、ODBCSpyやODBCTestと類似しています。