24

データベースにクエリを実行してテーブル全体を取得できるメソッドを作成しようとしています。

現在、メソッド内でデータを使用すると問題なく動作します。ただし、メソッドが結果を返すようにしたい。

私はjava.sql.SQLException: Operation not allowed after ResultSet closed現在のコードを取得しています。

どうすればこれを達成できますか?

public ResultSet select() {

    con = null;
    st = null;
    rs = null;

    try {
        con = DriverManager.getConnection(url, user, password);
        st = con.createStatement();

        rs = st.executeQuery("SELECT * FROM biler");
        /*
        if (rs.next()) {
            System.out.println(rs.getString("model"));
        }*/

    } catch (SQLException ex) {
        Logger lgr = Logger.getLogger(MySQL.class.getName());
        lgr.log(Level.SEVERE, ex.getMessage(), ex);

    } finally {
        try {
            if (rs != null) {
                rs.close();
            }
            if (st != null) {
                st.close();
            }
            if (con != null) {
                con.close();
            }

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(MySQL.class.getName());
            lgr.log(Level.WARNING, ex.getMessage(), ex);
        }
    }

    return rs;
}
4

8 に答える 8

4

私の前の誰もが、結果セットを渡すのは悪い考えだと言いました。c3p0のような接続プール ライブラリを使用している場合は、CachedRowSetとその実装CachedRowSetImplを安全に使用できます。これを使用すると、接続を閉じることができます。必要な場合にのみ接続を使用します。Java ドキュメントのスニペットを次に示します。

CachedRowSet オブジェクトは切断された行セットです。つまり、データ ソースへの接続を短時間しか使用しません。データを読み取って行を設定している間にデータ ソースに接続し、基になるデータ ソースに変更を反映している間に再度接続します。残りの時間は、データが変更されている間も含めて、CachedRowSet オブジェクトは切断されます。切断されていると、RowSet オブジェクトがよりスリムになるため、別のコンポーネントに渡すのがはるかに簡単になります。たとえば、切断された RowSet オブジェクトをシリアライズして、ネットワーク経由で携帯情報端末 (PDA) などのシン クライアントに渡すことができます。

以下は、クエリを実行して ResultSet を返すためのコード スニペットです。

public ResultSet getContent(String queryStr) {
    Connection conn = null;
    Statement stmt = null;
    ResultSet resultSet = null;
    CachedRowSetImpl crs = null;
    try {
        Connection conn = dataSource.getConnection();
        stmt = conn.createStatement();
        resultSet = stmt.executeQuery(queryStr);

        crs = new CachedRowSetImpl();
        crs.populate(resultSet);
    } catch (SQLException e) {
        throw new IllegalStateException("Unable to execute query: " + queryStr, e);
    }finally {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            LOGGER.error("Ignored", e);
        }
    }

    return crs;
}

以下は、c3p0 を使用してデータ ソースを作成するためのスニペットです。

 ComboPooledDataSource cpds = new ComboPooledDataSource();
            try {
                cpds.setDriverClass("<driver class>"); //loads the jdbc driver
            } catch (PropertyVetoException e) {
                e.printStackTrace();
                return;
            }
            cpds.setJdbcUrl("jdbc:<url>");
            cpds.setMinPoolSize(5);
            cpds.setAcquireIncrement(5);
            cpds.setMaxPoolSize(20);

 javax.sql.DataSource dataSource = cpds;
于 2014-06-21T18:20:12.847 に答える
1

を閉じているResultSetため、もう使用できません。

テーブルの内容を返すには、 を反復処理して、ResultSet行ごとの表現を作成する必要があります (Listおそらく で?)。おそらく、各行は何らかのエンティティを表し、行ごとにそのようなエンティティを作成します。

while (rs.next()) {
   list.add(new Entity(rs));
}
return list;

別の方法は、コールバック オブジェクトを提供することです。反復処理では、行ResultSetごとにそのオブジェクトを呼び出します。ResultSetそうすれば、テーブル全体を表すオブジェクトを作成する必要はありません (サイズが大きい場合は問題になる可能性があります)。

   while (rs.next()) {
      client.processResultSet(rs);
   }

クライアントが結果セット/ステートメント/接続を閉じられるようにするのは気が進まないでしょう。これらは、リソースのリークを避けるために慎重に管理する必要があり、1 か所で処理する方がはるかに優れています (できれば、それらを開いた場所の近くで!)。

注: Apache Commons DbUtils.closeQuietly()を使用して、connect/statement/resultset タプルを簡単かつ確実に閉じることができます (null と例外を適切に処理します)。

于 2013-02-13T12:25:40.307 に答える