ORA-01000 SQL例外が発生しました。だから私はそれに関連するいくつかのクエリがあります。
ループ内で準備済みステートメントを実行すると、この問題が発生しますか? (もちろん、私はsqlBatchを使ったかもしれません)注意:pStmtはループが終わると閉じられます。
{ //method try starts
String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
pStmt = obj.getConnection().prepareStatement(sql);
pStmt.setLong(1, subscriberID);
for (String language : additionalLangs) {
pStmt.setInt(2, Integer.parseInt(language));
pStmt.execute();
}
} //method/try ends
{ //finally starts
pStmt.close()
} //finally ends
Conn.createStatement()とconn.prepareStatement(sql)が単一の接続オブジェクトで複数回呼び出されるとどうなりますか?
編集1: 6. Weak/Soft参照文オブジェクトの使用は、漏洩防止に役立ちますか?
編集2: 1.プロジェクトに見つからない "statement.close()"をすべて見つけることができる方法はありますか。私はそれがメモリリークではないことを理解しています。しかし、ガベージコレクションに適したステートメント参照(close()が実行されない場合)を見つける必要がありますか?利用できるツールはありますか?それとも手動で分析する必要がありますか?
私がそれを理解するのを手伝ってください。
ORALCEマシンに移動して、sysdbaとしてsqlplusを起動します。
[Oracle@db01 ~]$ sqlplus / as sysdba
それから走りなさい
SELECT A.VALUE,
S.USERNAME,
S.SID,
S.SERIAL#
FROM V$SESSTAT A,
V$STATNAME B,
V$SESSION S
WHERE A.STATISTIC# = B.STATISTIC#
AND S.SID = A.SID
AND B.NAME = 'opened cursors current'
AND USERNAME = 'VELU';
できれば最後に私の答えを読んでください。
最大オープンカーソル数エラーであるORA-01000は、Oracleデータベース開発では非常に一般的なエラーです。 Javaのコンテキストでは、アプリケーションがデータベースインスタンスに設定されているカーソルよりも多くのResultSetを開こうとすると発生します。
一般的な原因は次のとおりです。
設定ミス
解決策:
カーソルリーク
この節では、カーソルの背後にある理論とJDBCの使用方法について説明します。背景を知る必要がない場合は、これを飛ばして 'Eliminating Leaks'に直接進んでください。
カーソルは、クエリの状態、具体的には読者がResultSet内にいる位置を保持するデータベース上のリソースです。各SELECT文にはカーソルがあり、PL/SQLストアドプロシージャは必要な数のカーソルを開いて使用できます。 Orafaq でカーソルについてもっと知ることができます。
データベースインスタンスは通常、いくつかの異なるスキーマ、多くの異なるユーザー、それぞれ複数セッションを提供します。これを行うために、すべてのスキーマ、ユーザー、およびセッションで使用可能な固定数のカーソルがあります。すべてのカーソルが開いていて(使用中)、新しいカーソルを必要とする要求が発生した場合、要求はORA-010000エラーで失敗します。
この番号は通常、インストール時にDBAによって設定されます。現在使用中のカーソルの数、最大数、および構成は、 Oracle SQL Developer の管理者機能でアクセスできます。 SQLからは次のように設定できます。
ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;
以下のJDBCオブジェクトは、以下のデータベースの概念と密接に関連しています。
JDBCはスレッドセーフです。スレッド間でさまざまなJDBCオブジェクトを受け渡しても大丈夫です。
たとえば、1つのスレッドで接続を作成できます。別のスレッドがこの接続を使用してPreparedStatementを作成し、3番目のスレッドが結果セットを処理できます。唯一の大きな制限は、1つのPreparedStatementで複数のResultSetを同時に開くことができないことです。 Oracle DBは、接続ごとに複数の(パラレル)操作をサポートしますか? を参照してください。
データベースのコミットは接続上で行われるため、その接続上のすべてのDML(INSERT、UPDATEおよびDELETE)は一緒にコミットされます。したがって、同時に複数のトランザクションをサポートする場合は、各同時トランザクションに対して少なくとも1つの接続が必要です。
ResultSetを実行する典型的な例は次のとおりです。
Statement stmt = conn.createStatement();
try {
ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
try {
while ( rs.next() ) {
System.out.println( "Name: " + rs.getString("FULL_NAME") );
}
} finally {
try { rs.close(); } catch (Exception ignore) { }
}
} finally {
try { stmt.close(); } catch (Exception ignore) { }
}
Finally節は、close()によって発生した例外を無視することに注意してください。
Java 7では、Oracleは AutoCloseableインタフェース を導入しました。これは、Java 6の定型句の大部分をいくつかのNice構文糖で置き換えます。
JDBCオブジェクトは、ローカル変数、オブジェクトインスタンス、およびクラスメンバに安全に保持できます。一般的には、次のことをお勧めします。
ただし、例外が1つあります。EJB、またはサーブレット/ JSPコンテナを使用している場合は、厳密なスレッドモデルに従う必要があります。
JDBCリークの検出と排除に役立つ、利用可能なプロセスとツールがいくつかあります。
開発中 - 早くバグを捉えることは断然最良の方法です:
開発慣行:良い開発慣行は、ソフトウェアが開発者の机を離れる前に、ソフトウェアのバグの数を減らすはずです。具体的な方法は次のとおりです。
静的コード分析:静的コード分析を実行するには、優れた Findbugs のようなツールを使用してください。これはclose()が正しく処理されていない多くの場所を拾います。 FindbugsにはEclipse用のプラグインがありますが、単発のためにスタンドアロンで実行され、Jenkins CIや他のビルドツールに統合されています。
実行時に
保持力とコミット
実行時のロギング.
デバッグ用のJDBCドライバをプロジェクトに追加できます(デバッグ用 - 実際にはデプロイしないでください)。一例(私はそれを使ったことがない)は log4jdbc です。次に、このファイルを簡単に分析して、どの実行に対応するクローズがないかを確認する必要があります。潜在的な問題がある場合は、開始と終了を数えることが強調表示されます。
弱い参照と弱い参照は、適切であると判断されたときにいつでもJVMが参照先をガベージコレクションできるようにオブジェクトを参照できるようにする方法です(そのオブジェクトへの強い参照チェーンがないと仮定します)。
コンストラクタでReferenceQueueを弱い参照または弱い参照に渡すと、オブジェクトが発生したときにGCが実行されたときに(まったく発生した場合)、オブジェクトはReferenceQueueに配置されます。この方法では、オブジェクトのファイナライズと対話し、その時点でオブジェクトを閉じるかファイナライズすることができます。
ファントム参照は少し奇妙です。その目的はファイナライズを制御することだけですが、元のオブジェクトへの参照を取得することはできないので、close()メソッドを呼び出すのは困難になります。
ただし、GCを実行するタイミングを制御することを試みることはめったにありません(Weak、Soft、およびPhantomReferencesは、オブジェクトがGCのためにキューに入れられたことをafter after factに知らせます)。実際、JVMのメモリ容量が大きい場合(例:-Xmx2000m)、オブジェクトをnever GCすることがありますが、それでもORA-01000が発生します。 JVMメモリがプログラムの要件に比べて小さい場合は、ResultSetオブジェクトとPreparedStatementオブジェクトが作成直後(それらから読み取ることができる前)にGCされている可能性があります。これはプログラムに失敗する可能性があります。
TL; DR:弱い参照メカニズムは、StatementオブジェクトとResultSetオブジェクトを管理して閉じるための良い方法ではありません。
もう少し理解を深めています。
Sysdbaとしてログインします。
PuTTY(Oracleログイン)の場合:
[Oracle@db01 ~]$ sqlplus / as sysdba
SqlPlusの場合:
ユーザー名:sys as sysdba
alter session set session_cached_cursors=0
select * from V$PARAMETER where name='session_cached_cursors'
SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname b, v$parameter p WHERE a.statistic# = b.statistic# AND b.name = 'opened cursors current' AND p.name= 'open_cursors' GROUP BY p.value;
SELECT a.value, s.username, s.sid, s.serial#
FROM v$sesstat a, v$statname b, v$session s
WHERE a.statistic# = b.statistic# AND s.sid=a.sid
AND b.name = 'opened cursors current' AND username = 'SCHEMA_NAME_IN_CAPS'
SELECT oc.sql_text, s.sid
FROM v$open_cursor oc, v$session s
WHERE OC.sid = S.sid
AND s.sid=1604
AND OC.USER_NAME ='SCHEMA_NAME_IN_CAPS'
今すぐコードをデバッグしてお楽しみください! :)
このようにコードを修正してください。
try
{ //method try starts
String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
pStmt = obj.getConnection().prepareStatement(sql);
pStmt.setLong(1, subscriberID);
for (String language : additionalLangs) {
pStmt.setInt(2, Integer.parseInt(language));
pStmt.execute();
}
} //method/try ends
finally
{ //finally starts
pStmt.close()
}
本当に、あなたは本当にあなたのpStatement、接続および結果を閉じているということですか?
開いているオブジェクトを分析するには、ステートマント、接続、および結果オブジェクトをコードで囲む委任パターンを暗黙的に指定します。そのため、オブジェクトが正常に閉じられるかどうかがわかります。
PStmt = obj .getConnection()。prepareStatement(sql);の例
class obj{
public Connection getConnection(){
return new ConnectionDelegator(...here create your connection object and put it into ...);
}
}
class ConnectionDelegator implements Connection{
Connection delegates;
public ConnectionDelegator(Connection con){
this.delegates = con;
}
public Statement prepareStatement(String sql){
return delegates.prepareStatement(sql);
}
public void close(){
try{
delegates.close();
}finally{
log.debug(delegates.toString() + " was closed");
}
}
}
アプリケーションがアプリケーションサーバーとしてOracle WebLogicで実行されているJava EEアプリケーションである場合、この問題の考えられる原因はWebLogicの Statement Cache Size 設定です。
特定のデータソースの文キャッシュサイズの設定がOracleデータベースの最大オープンカーソル数の設定とほぼ同じかそれより大きい場合、WebLogicによってオープンに保持されているキャッシュされたSQL文によってすべてのオープンカーソルが消費されます。 ORA-01000エラーにあります。
これに対処するには、Oracleデータベースを指す各WebLogicデータソースのStatement Cache Size設定を、データベースの最大カーソル数設定よりも大幅に少なくします。
WebLogic 10アドミンコンソールでは、各データソースのStatement Cache Size設定は、[サービス](左側のナビゲーション)> [データソース]>(個々のデータソース)> [接続プール]タブで確認できます。
今日も同じ問題(ORA-01000)に直面しました。 try {}内にforループを使用して、Oracle DB内でSELECT文を何度も(パラメータを変更するたびに)実行し、最後の{}内には、いつものようにResultset、PreparedStatementおよびConnectionを閉じるコードがあります。 。しかし、特定のループ数(1000)に達するとすぐに、オープンカーソルが多すぎるというOracleエラーが発生しました。
上記のAndrew Alcockによる投稿に基づいて、insideループのように、データを取得した後、再度ループする前に各結果セットと各文を閉じて、問題を解決しました。
さらに、今回と同様に、別のOracle DB(ORA-01000)のInsert文の別のループでも、まったく同じ問題が発生しました。今回は300文の後です。これも同じ方法で解決されたため、PreparedStatementまたはResultSet、あるいはその両方が、クローズされるまでオープンカーソルとしてカウントされます。
私もこの問題に直面していました。
Java.sql.SQLException: - ORA-01000: maximum open cursors exceeded
DaoレイヤにSpring Framework with Spring JDBCを使っていました。
私のアプリケーションはどういうわけかカーソルをリークし、数分かそこら後に、それは私にこの例外を与えていました。
たくさんの徹底的なデバッグと分析の後、私はTableのうちの1つでIndexing、Primary Key and Unique Constraintsに問題があることを知りました - クエリ私は実行していました。
私のアプリケーションはColumnsを誤って更新しようとしていましたIndexed。そのため、私のアプリケーションがインデックス付きカラムに対してupdateクエリを実行しているときはいつでも、データベースは更新された値に基づいてインデックスの再作成を試みていました。 カーソルをリークしていました。
クエリで検索するのに使用された列に適切なインデックスを作成し、そして必要に応じて適切な制約を適用することで問題を解決することができました。
開かれたSQLを見つけるためのクエリ。
SELECT s.machine, oc.user_name, oc.sql_text, count(1)
FROM v$open_cursor oc, v$session s
WHERE oc.sid = s.sid
and S.USERNAME='XXXX'
GROUP BY user_name, sql_text, machine
HAVING COUNT(1) > 2
ORDER BY count(1) DESC
Autocommit = trueを設定しましたか?そうでなければこれを試してください:
{ //method try starts
String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
Connection conn = obj.getConnection()
pStmt = conn.prepareStatement(sql);
for (String language : additionalLangs) {
pStmt.setLong(1, subscriberID);
pStmt.setInt(2, Integer.parseInt(language));
pStmt.execute();
conn.commit();
}
} //method/try ends {
//finally starts
pStmt.close()
} //finally ends
今回のケースでは、Hibernateを使用していて、同じHibernateマップエンティティを参照する多くの変数がありました。これらの参照を作成してループで保存していました。各参照はカーソルを開き、開いたままにしました。
コードの実行中に 開いているカーソルの数をチェックするためのクエリ を使用し、デバッガを使用して選択的にコメントアウトすることでこれを発見しました。
それぞれの新しい参照が別のカーソルを開く理由について - 問題のエンティティはそれにマッピングされた他のエンティティのコレクションを持っていました、そして私はこれと関係があると思います(おそらくこれだけではなくフェッチモードとキャッシュ設定)。 Hibernate自体は クローズに失敗することに関するバグ 開いているカーソルを持っていました、これらは後のバージョンで修正されたように見えますが。
とにかく同じエンティティに対してそれほど多くの重複する参照を持つ必要はないので、解決策はそれらの冗長な参照をすべて作成して保持するのをやめることでした。いったん私たちがその問題をやめたとき。
私は、Oracle 10gに接続しているWildFlyとTomcatのデータソースでこの問題を抱えていました。
特定の条件下で、statement.close()が呼び出されてもステートメントが閉じられないことがわかりました。問題は、使用しているOracleドライバ、ojdbc7.jarにあります。このドライバはOracle 12cおよび11gを対象としており、Oracle 10gで使用するといくつか問題があるように思われるので、私はojdbc5.jarにダウングレードしてもすべて正常に動作しています。
1000回以上の繰り返しでdbにクエリを実行していたため、同じ問題に直面しました。私はtryを使用し、最後に私のコードで使用しました。しかし、まだエラーを受けていました。
これを解決するために、私はOracle dbにログインして、以下のクエリを実行しました。
ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;
そして、これで私の問題はすぐに解決しました。
この問題は主に接続プールを使用している場合に発生します。接続を閉じると、その接続は接続プールに戻り、データベースへの接続が開いたままであるため、その接続に関連付けられているカーソルがすべて閉じられることはありません。そのため、プール内の接続のアイドル接続時間を短縮することも考えられます。接続がアイドル状態のまま10秒間待機するたびに、データベースへの接続が閉じられ、新しい接続が作成されてプールに入れられます。
バッチ処理を使用すると、オーバーヘッドが少なくなります。例については、次のリンクを参照してください。 http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm