首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >返回ResultSet

返回ResultSet
EN

Stack Overflow用户
提问于 2013-02-13 12:23:49
回答 8查看 97.9K关注 0票数 26

我正在尝试创建一个方法,在那里我可以查询我的数据库并检索整个表。

目前,如果我在方法中使用数据,它就能正常工作。但是,我希望方法返回结果。

我得到了一个关于当前代码的java.sql.SQLException: Operation not allowed after ResultSet closed

我怎样才能做到这一点?

代码语言:javascript
复制
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;
}
EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2013-02-13 12:30:17

您不应该通过公共方法传递ResultSet。这很容易导致资源泄漏,因为您被迫保持语句和连接处于打开状态。关闭它们将隐式关闭结果集。但是,保持它们的打开会导致它们在周围晃动,并导致DB在太多的资源打开时耗尽资源。

将它映射到像这样的Javabeans集合中,然后返回它:

代码语言:javascript
复制
public List<Biler> list() throws SQLException {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    List<Biler> bilers = new ArrayList<Biler>();

    try {
        connection = database.getConnection();
        statement = connection.prepareStatement("SELECT id, name, value FROM Biler");
        resultSet = statement.executeQuery();

        while (resultSet.next()) {
            Biler biler = new Biler();
            biler.setId(resultSet.getLong("id"));
            biler.setName(resultSet.getString("name"));
            biler.setValue(resultSet.getInt("value"));
            bilers.add(biler);
        }
    } finally {
        if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
        if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
        if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
    }

    return bilers;
}

或者,如果您已经使用了Java 7,只需使用试着用资源语句就可以自动关闭这些资源:

代码语言:javascript
复制
public List<Biler> list() throws SQLException {
    List<Biler> bilers = new ArrayList<Biler>();

    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement("SELECT id, name, value FROM Biler");
        ResultSet resultSet = statement.executeQuery();
    ) {
        while (resultSet.next()) {
            Biler biler = new Biler();
            biler.setId(resultSet.getLong("id"));
            biler.setName(resultSet.getString("name"));
            biler.setValue(resultSet.getInt("value"));
            bilers.add(biler);
        }
    }

    return bilers;
}

顺便说一下,您根本不应该将ConnectionStatementResultSet声明为实例变量(重大线程安全问题!),也不应该在此时吞食SQLException (调用者将不知道发生了问题),也不应该关闭同一个try中的资源(例如,结果集关闭抛出异常,那么语句和连接仍然打开)。所有这些问题都在上面的代码片段中得到了解决。

票数 61
EN

Stack Overflow用户

发布于 2013-02-13 12:59:48

如果您不知道检索时间时对ResultSet的要求是什么,我建议将完整的内容映射成如下所示的地图:

代码语言:javascript
复制
    List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
    Map<String, Object> row = null;

    ResultSetMetaData metaData = rs.getMetaData();
    Integer columnCount = metaData.getColumnCount();

    while (rs.next()) {
        row = new HashMap<String, Object>();
        for (int i = 1; i <= columnCount; i++) {
            row.put(metaData.getColumnName(i), rs.getObject(i));
        }
        resultList.add(row);
    }

因此,基本上您有与ResultSet相同的东西(没有ResultSetMetaData)。

票数 16
EN

Stack Overflow用户

发布于 2013-02-13 12:26:08

好吧,dofinally-block中调用rs.close()

这基本上是个好主意,因为您应该关闭所有资源(连接、语句、结果集,.)。

但你必须在使用它们之后关闭它们。

至少有三种可能的解决办法:

  1. 不要关闭结果集(和连接,.)并要求调用方调用单独的“关闭”方法。 这基本上意味着,调用者现在需要记住呼叫关闭,而不是真正使事情变得更容易。
  2. 让调用者传入一个传递结果集的类,并在您的方法中调用它。 这是可行的,但可能会变得有点冗长,因为对于要在结果集中执行的每一个代码块,您都需要一个接口子类(可能是匿名内部类)。 接口如下所示: 公共接口ResultSetConsumer {公共T消耗(ResultSet rs);} 您的select方法如下所示: 公共列表选择(字符串查询,ResultSetConsumer使用者){ Connection = null;语句st = null;ResultSet rs = null;尝试{ con = DriverManager.getConnection(url,user,password);st = con.createStatement();rs =st.executeQuery(查询);List result =新ArrayList();while (rs.next()) { result.add(consumer.consume(rs));} catch (SQLException ex) { // logging }最后{ try { if (rs = null) { rs.close();} if (st != null) { st.close();} if (con = null) { con.close();} catch (SQLException ex) { Logger = Logger.getLogger(MySQL.class.getName());lgr.log(Level.WARNING,ex.getMessage(),ex);}返回;}
  3. select方法中执行所有工作,并返回一些List作为结果。 这可能是使用最广泛的一种方法:迭代结果集并将数据转换为您自己的DTO中的自定义数据并返回这些数据。
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14853508

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档