2009-09-17 22 views
6

Oracleでは、カーソルを戻すストアド・プロシージャをコールするためにSpring SimpleJdbcCallを使用しています。 SimpleJdbcCallはカーソルを閉じておらず、しばらくしてから最大オープンカーソルを超えているようです。ORA-01000:Spring SimpleJDBCCallを使用すると最大オープン・カーソルを超えました

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

これは経験したことがありますが、一見答えが得られていないフォーラムには、他にもいくつかの人がいます。私は春/オラクルサポートのバグだと思われます。

このバグは非常に重要であり、今後のSpring JDBCの使用に影響する可能性があります。

問題をSpringコードにトラッキングするか、問題を回避する回避策を見つけた人がいますか?

私たちはSpring 2.5.6を使用しています。

... 
SimpleJdbcCall call = new SimpleJdbcCall(dataSource); 

Map params = new HashMap(); 
params.put("remote_user", session.getAttribute("cas_username")); 

Map result = call 
    .withSchemaName("urs") 
    .withCatalogName("ursWeb") 
    .withProcedureName("get_roles") 
    .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper()) 
    .execute(params); 
List roles = (List)result.get("rolesCur") 

コードの古いバージョンを使用しない:ここでは

は正しくカーソル経由のprocリターンが結果セットを閉じることがないように見えるSimpleJdbcCallを使用してコードの新しいバージョンですSpring JDBCにはこの問題はありません。

oracleConnection = dataSource.getConnection(); 
callable = oracleConnection.prepareCall(
     "{ call urs.ursweb.get_roles(?, ?) }" ); 
callable.setString(1, (String)session.getAttribute("cas_username")); 
callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); 
callable.execute(); 
ResultSet rset = (ResultSet)callable.getObject(2); 
... do stuff with the result set 
if (rset != null) rset.close(); // Explicitly close the resultset 
if (callable != null) callable.close(); //Close the callable 
if (oracleConnection != null) oracleConnection.close(); //Close the connection 

Spring JDBCはrset.close()を呼び出していないようです。古いコードでその行をコメントアウトすると、負荷テスト後に同じデータベース例外が発生します。

+3

SimpleJdbcCallの使い方を示すコードを投稿してください。これがSpringのバグである可能性は非常に低く、特にOracleが結果セットを処理する非標準的な方法を考えると、使用する可能性は高いです。 – skaffman

+1

+1 with skaffman。問題が見つからない場合は、http://jira.springframework.org/でバグを報告する前に、堅実なテストケースを構築してみてください。 –

答えて

7

多くのテストの結果、この問題が修正されました。これは、SpringフレームワークとOracleクライアントとOracle DBの使い方を組み合わせたものです。Oracle JDBCクライアントのメタデータ・コールを使用していた新しいSimpleJDBCCallsを作成していましたが、これはクローズされずにクリーンアップされていないカーソルとして戻されました。これは、SpringのJDBCフレームワークでメタデータをどのように呼び出すか、カーソルを閉じないというバグだと私は考えています。 Springは、メタデータをカーソルからコピーして適切に閉じなければなりません。ベスト・プラクティスを使用すると、バグが出現しないので、私は春にjira問題を開くのに気にしませんでした。

この問題を修正するには、OPEN_CURSORSやその他のパラメータを調整するのが間違った方法で、表示されないようにするだけです。

SimpleJDBCCallをシングルトンDAOに移動して修正したので、私たちが呼んでいる各Oracle Procで1つのカーソルしかオープンしていません。これらのカーソルは、アプリの生涯にわたって公開されています。これはバグだと考えています。 OPEN_CURSORSがSimpleJDBCCallオブジェクトの数よりも大きい場合は、面倒なことはありません。

+5

もしあなたがバグだと思ったら、これを報告して欲しい。 –

1

私はそれが春ではないことを約束することができます。私は2005年に公開されたSpring 1.xアプリを開発して以来、接続を漏らしていません。 (WebLogic 9.、JDK 5)。あなたはあなたのリソースを適切に閉じているわけではありません。

接続プールを使用していますか?どのアプリケーションサーバーに展開していますか?どのバージョンのSpring?オラクル? Java?詳細はどうぞ。

-3

ソリューションは、春ではありませんが、Oracleに:あなたは、デフォルトのOracle 50

より高いいくつかの値にOPEN_CURSORS初期化パラメータを設定する必要があります - おそらくそれが変わったの、少なくともとして-の8I、 - - JDBC PreparedStatementオブジェクトを開いたままにしない限り、JDBC PreparedStatementオブジェクトを再解析します。これは高価で、ほとんどの人は再送信された開かれたステートメントの固定プールを維持してしまいます。

(10Iのドキュメントで簡単に見を取って、彼らは明示的にOCIドライバはPreparedStatementsのをキャッシュすることに注意してください、私はネイティブドライバがまだそれらを毎回再作成することを仮定している)

+2

これはリソースリークです。リソースリークの解決策は停止することです漏れ、水を追加しないでください。 –

+1

@Andrew - あなたのdownvoteと一緒にコメントしていただきありがとうございます。しかし、1990年代の初めからOracleと協力してきた私は、私の答えに立っています。すぐに使える構成は、複雑なアプリケーションには適していません。さらに、OPはSpringを使用しています。これは、それ自体の後にクリーンアップするのに非常に適しています。営業担当者がどこかでリソースリークを書いた可能性はありますが、明示的な接続管理を行っている場合よりもはるかに少ない可能性があります。 – kdgregory

+0

すべての投稿を読み返すと、私は返答後2ヵ月後にOPが受け入れた回答を投稿したことがわかりました。これは、実際にはSpringのリソースリークであったことを示しています。しかし、想定されるリークがSpringがメタデータをキャッシュしようとしていたことを考えると、私は2番目のパラグラフを参照して、この答えに依頼します。 – kdgregory

-2

OracleのOPEN_CURSORSがキー大丈夫です。明らかにオープンしているカーソルはわずかしかなく、Oracle XEに対応した小型の24x7アプリがあります。 OPEN_CURSORS初期化値を> 300に設定するまで、断続的な最大オープンカーソルエラーが発生しました。

+4

これはリソースリークですが、リソースリークの解決策は漏れを止めることです。水を追加しないでください。 –

2

オーバーヘッドがあるため、OPEN_CURSORSをより高い値と高い値に設定するだけで実際の問題やエラーを補うことができますあなたのコード。

私は...

この春の側での経験を持っているが、我々はORA-01000エラーで多くの問題を持っていたアプリに取り組み、常にOPEN_CURSORSはただ問題はしばらく離れて行かせた調整はありません
3

私はBLOBを読んでいたときにこの問題を抱えています。主な原因は、私もテーブルを更新していて、更新句を含むStatementが自動的に閉じられなかったことでした。厄介なカーソルリークはすべてのフリーカーソルを食べます。 statement.close()を明示的に呼び出した後、エラーは消えます。

モラル - 常にすべてを閉じる、ステートメントを廃棄した後で自動閉鎖に頼らないでください。

関連する問題