2011年9月17日土曜日

JDBCでORA-01000が出た場合の対処

OPEN_CURSORS初期パラメータが適切に設定されていない場合や、
JDBCを使用したアプリケーションでリソース開放を適切に行っていない場合に「ORA-01000: 最大オープン・カーソル数を超えました。」が発生する場合があります。

JDBCを使用したアプリケーションが適切にリソース開放を行えているのであれば、一つのDBセッションで発行するSQLの種類をもとにOPEN_CURSORSを設定してあげることができます。
マニュアルには、「OPEN_CURSORSに指定する値が実際に必要な数より大きくても、セッションでオープンするカーソル数が指定した値よりも小さければ、余分なオーバーヘッドはありません。」と書かれているのでかなり余裕をもった値を設定すればいいのかなとも思います。

OPEN_CURSORSを変更する方法

現在のOPEN_CURSORSの値の確認方法

sqlplusから下記コマンドを実行することにより確認できます。
show parameters open_cursors

※「SELECT ON V_$PARAMETERオブジェクト権限」が必要なので、権限をもったユーザでログインする必要があります。

OPEN_CURSORSの変更方法

例えば、1000に変更したい場
alter system set open_cursors = 1000;

上記コマンドを実行したあとのOPEN_CURSORS値
SQL> show parameters open_cursors;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
open_cursors                         integer     1000

※「ALTER SYSTEMシステム権限」を持つユーザで実行する必要があります。

アプリケーションの実装を見直す場合

必ずリソース開放がされていることを確認する必要があります。ここで言うリソースとは、java.sql.Statementのことであってjava.sql.ResultSetでありません。
注意しないといけないのは、DML文に対応するStatementも1カーソルとしてカウントされてしまうことです。

※普通なシステム開発では、フレームワークでリソース開放してくれるはずなんでアプリでリソース開放なんてする必要はないはずです。
昔いけてないフレームワークでリソース開放してくれずにこのエラーが頻発したことありましたが・・・。

正しいリソース開放の例
        // DML文の場合
        PreparedStatement statement = connection.prepareStatement(
                "SQL文");
        try {
            statement.executeUpdate();
        } finally {
            // finallyでstatementをcloseする。
            statement.close();
        }

        // selectの場合
        PreparedStatement select = connection.prepareStatement(
                "SQL文");
        try {
            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                // 処理
            }
        } finally {
            // finallyでstatementをcloseする。
            // ResultSetは、statementクローズ時にcloseされる。
            select.close();
        }