0

データベースというクラスがあります。

    public class Database {
    public Connection connect = null;
    public Statement st = null;
    public PreparedStatement ps = null;
    public ResultSet rs = null;

    public boolean connectDB() throws Exception {
      try {

      Class.forName("com.mysql.jdbc.Driver");

      connect = DriverManager
        .getConnection("jdbc:mysql://localhost/ots?"
              + "user=root&password=mongolia");
    } catch (Exception e) {
      System.out.println(e);
    }
    return true;
   }

    public void disconnectDB() {
    try {
      if (rs != null) {
        rs.close();
      }

      if (st != null) {
        st.close();
      }

      if (connect != null) {
        connect.close();
      }
    } catch (Exception e) {

    }
    }

     } 

データベースクラスを拡張しているuserというクラス

public class User extends Database {
    public ResultSet fetchTable(){
        try{
            connectDB();            
            st = connect.createStatement();
            rs = st.executeQuery("SELECT * FROM user");         
        }catch(Exception e){
            System.out.println(e);
        }finally{
            disconnectDB();
        }
        return rs;
    }
  }
//Inside JSP page
  User user = new User();
  ResultSet data = user.fetchTable();

  //getting exception in the data.next() function
  //java.sql.SQLException: Operation not allowed after ResultSet closed

  while(data.next()){
        out.println("<p>"+data.getInt(0)+"</p>");
   }

//getting exception in the data.next() function
//java.sql.SQLException: Operation not allowed after ResultSet closed
4

1 に答える 1

6

例外は完全に予想されます。DBを接続し、結果セットを取得し、DBと結果セットを閉じてから、閉じた結果セットにアクセスしようとしています。

これは、JDBCでの動作とは異なります。

List<User>結果セットを取得した直後に結果セットをマップし、結果セットを閉じてList<User>代わりに返す必要があります。

いくつかの具体的な例については、この質問の答えに進んでください。JDBCドライバーは、空のResultSetで「ResultSetClosed」例外をスローします。


具体的な問題とは関係なく、コードには他にも深刻な問題があります。特に、メソッドローカル変数ではなくインスタンス変数としてConnectionStatementを宣言しました。ResultSet同じインスタンスが複数のスレッド間で共有されている場合(2人以上のユーザーが同時にWebアプリケーションにアクセスした場合に発生する可能性があります)、これは非常に失敗します。私もそれを修正します。


更新:これまでに投稿された他の回答では、disconnectDB()呼び出しを削除するか、他のメソッドの結果セットを反復処理した後にのみ呼び出すことをお勧めします。これは間違っています。メソッドから抜け出してはいけません。ResultSetコードは依然としてスレッドセーフではなく、例外が発生した場合でもリソースリークのリスクがあります。まったく同じメソッドブロックで作成、使用、および閉じる必要があります。前述の質問からコピーして貼り付けた適切なアプローチは次のとおりです。

public List<User> list() throws SQLException {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    List<User> users = new ArrayList<User>();

    try {
        connection = database.getConnection();
        statement = connection.prepareStatement("SELECT id, username, email, age FROM user");
        resultSet = statement.executeQuery();
        while (resultSet.next()) {
            users.add(new User(
                resultSet.getLong("id"),
                resultSet.getString("username"),
                resultSet.getString("email"),
                resultSet.getInteger("age")));
        }
    } finally {
        close(resultSet, statement, connection);
    }

    return users;
}
于 2012-12-15T20:57:56.700 に答える