コードがwhile(rs.next())
ループに到達するとすぐに、ResultSet
is closed例外が生成されます。この例外の原因と修正方法を教えてください。
編集:コード内で、while(rs.next())
ループを別の(rs2.next())
、両方の結果セットは同じDBからのものですが、これは問題ですか?
最初のステートメントから結果セットを走査する前に、同じ接続で別のステートメントを実行したように聞こえます。同じデータベースからの2つの結果セットの処理をネストしている場合、何か間違ったことをしていることになります。これらのセットの組み合わせは、データベース側で行う必要があります。
これは、使用しているドライバーなど、さまざまな理由で発生する可能性があります。
a)一部のドライバーは、ネストされたステートメントを許可しません。ドライバーがJDBC 3.0をサポートしているかどうかに応じて、Statementオブジェクトを作成するときに3番目のパラメーターを確認する必要があります。たとえば、FirebirdのJayBirdドライバーでも同じ問題がありましたが、postgresドライバーではコードは問題なく機能しました。次に、3番目のパラメーターをcreateStatementメソッド呼び出しに追加し、ResultSet.HOLD_CURSORS_OVER_COMMITに設定すると、コードがFirebirdでも正常に機能し始めました。
static void testNestedRS() throws SQLException {
Connection con =null;
try {
// GET A CONNECTION
con = ConexionDesdeArchivo.obtenerConexion("examen-dest");
String sql1 = "select * from reportes_clasificacion";
Statement st1 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs1 = null;
try {
// EXECUTE THE FIRST QRY
rs1 = st1.executeQuery(sql1);
while (rs1.next()) {
// THIS LINE WILL BE PRINTED JUST ONCE ON
// SOME DRIVERS UNLESS YOU CREATE THE STATEMENT
// WITH 3 PARAMETERS USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
System.out.println("ST1 Row #: " + rs1.getRow());
String sql2 = "select * from reportes";
Statement st2 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// EXECUTE THE SECOND QRY. THIS CLOSES THE FIRST
// ResultSet ON SOME DRIVERS WITHOUT USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
st2.executeQuery(sql2);
st2.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs1.close();
st1.close();
}
} catch (SQLException e) {
} finally {
con.close();
}
}
b)コードにバグがある可能性があります。 Statementオブジェクトを再利用することはできません。同じステートメントオブジェクトに対してクエリを再実行すると、そのステートメントに関連付けられている開いている結果セットはすべて閉じられます。ステートメントを閉じていないことを確認してください。
また、各ステートメントから開くことができる結果セットは1つのみです。したがって、2つの結果セットを同時に繰り返し処理する場合は、それらが異なるステートメントで実行されることを確認してください。 1つのステートメントで2番目の結果セットを開くと、最初のステートメントが暗黙的に閉じられます。 http://Java.Sun.com/javase/6/docs/api/Java/sql/Statement.html
例外は、結果が閉じていることを示しています。コードを調べて、ResultSet.close()
呼び出しを発行するすべての場所を探す必要があります。 Statement.close()
およびConnection.close()
も探してください。確かに、それらの1つはrs.next()
が呼び出される前に呼び出されます。
Connection
またはStatement
を作成したResultSet
を閉じた可能性があります。これにより、ResultSet
も閉じられます。
適切なjdbc呼び出しは次のようになります。
_try {
Connection conn;
Statement stmt;
ResultSet rs;
try {
conn = DriverManager.getConnection(myUrl,"","");
stmt = conn.createStatement();
rs = stmt.executeQuery(myQuery);
while ( rs.next() ) {
// process results
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
} finally {
// you should release your resources here
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
_
結果セットから結果を取得した後にのみ、接続(またはステートメント)を閉じることができます。最も安全な方法は、finally
ブロックで行うことです。ただし、close()
はSqlException
もスローする可能性があるため、他の_try-catch
_ブロックもスローされます。
同じエラーが発生しましたが、データベースを実行および更新するために同じステートメントインターフェイスオブジェクトを使用していた場合にのみすべてが正しかったです。クエリを更新および実行するためにステートメントインターフェイスの異なるオブジェクトを使用して分離した後、このエラーを解決しました。つまり、これを取り除くには、クエリの更新と実行の両方に同じステートメントオブジェクトを使用しないでください。
このコードがstatic
として実行されているメソッドを宣言したかどうかを確認します。 static
である場合、他のスレッドがResultSet
をリセットしている可能性があります。
rs.nextを実行する前に、すべてのステートメントと結果セットを閉じていることを確認してください。 Finalyはこれを保証します
public boolean flowExists( Integer idStatusPrevious, Integer idStatus, Connection connection ) {
LogUtil.logRequestMethod();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = connection.prepareStatement( Constants.SCRIPT_SELECT_FIND_FLOW_STATUS_BY_STATUS );
ps.setInt( 1, idStatusPrevious );
ps.setInt( 2, idStatus );
rs = ps.executeQuery();
Long count = 0L;
if ( rs != null ) {
while ( rs.next() ) {
count = rs.getLong( 1 );
break;
}
}
LogUtil.logSuccessMethod();
return count > 0L;
} catch ( Exception e ) {
String errorMsg = String
.format( Constants.ERROR_FINALIZED_METHOD, ( e.getMessage() != null ? e.getMessage() : "" ) );
LogUtil.logError( errorMsg, e );
throw new FatalException( errorMsg );
} finally {
rs.close();
ps.close();
}
ResultSetClosedException
は、2つの理由でスローされる可能性があります。
1.)他のすべての接続を閉じずに、データベースへの別の接続を開きました。
2.)ResultSetが値を返さない場合があります。したがって、ResultSet Javaからデータにアクセスしようとすると、ResultSetClosedException
がスローされます。