【问题标题】:Is there any way of getting resultset after preparedstatement closed ? ( java )有什么方法可以在preparedstatement 关闭后获得结果集? (爪哇)
【发布时间】:2017-06-10 04:45:41
【问题描述】:

我做了一个静态方法来执行下面这样的查询

(这是在 ServerProcess 类中)

public static ResultSet insertRow(Connection conn, String query){
    PreparedStatement pstmt = conn.prepareStatement(query);
    ResultSet rs = pstmt.executeQuery();
    pstmt.close();
    return rs;
}

并尝试从此处获取和使用结果集

ResultSet rs = ServerProcess.insertRow(conn, query)
    while(rs.next()){
    String nameOfEachOne = rs.getString("MEMBER_NAME");
    System.out.println(nameOfEachOne);  
}

但是,据我所知,一旦语句(或preparedstatement)关闭,结果集必然会作为连锁反应而关闭。

我想以某种方式使用它,但我不知道该怎么做。语句结束后有什么方法可以获取信息集?

【问题讨论】:

  • preparedstatement 关闭后有什么方法可以获取结果集? (java) 没有
  • 假设post 讨论更多关于您的问题及其解决方案。
  • 是的,我知道这听起来很荒谬,但我只是好奇,想知道是否有什么好主意。
  • 提供回调 - 或使用 Spring 的 JdbcTemplate

标签: java sql prepared-statement resultset


【解决方案1】:

理想情况下,您根本不会公开这样的 ResultSet,它是一个非常可变/声明的对象。但是,如果您想提供它并仍然关闭它,您可以通过 lambda 函数使用它:

@FunctionalInterface interface SQLConsumer<T> {
    public void accept(T t) throws SQLException; //default functional interfaces can't throw
}

public void query(String sql, SQLConsumer<? super ResultSet> action) {
    ResultSet rs = /* various jdbc code */;
    action.accept(rs);
    rs.close(); //and other resources
}

//In usage:
query("SELECT * FROM my_table", rs -> {
    String s = rs.getString(1); //example
});

当然,您可以制作类似这样的各种方法,I've actually done abstraction 我自己也可以这样用于跨不同 RDBMS 的个人项目。

【讨论】:

  • 感谢您的友好回答。 “lambda”这个词看起来很难,让我想起了物理和数学:)我今天会试试!
  • 这里的 lambda 本质上是一种“匿名方法”(如匿名类)。它与数学定义的相似之处仅在于它表示一个函数(但不是物理学,因为那是波长)
【解决方案2】:

不,当父 PreparedStatement 已关闭时,您无法接收 ResultSet 或从中读取任何内容。

您可以做的是与消费者合作,该消费者在您关闭 PreparedStatement 之前读取 ResultSet,然后返回您需要的任何业务对象:

消费者界面:

@FunctionalInterface
public interface SQLConsumer<T extends ResultSet, E>// where E is going to be your Business-Object Type
{
    E accept(T resultSet) throws IOException;
}

该方法现在返回解析器返回的内容,但会正确关闭所有内容:

public static <E> E insertRow(Connection conn, String query, SQLConsumer<? super ResultSet, ? extends E> parser)
{
    E result;

    // use the try-with-resources functionality
    try (PreparedStatement pstmt = conn.prepareStatement(query)
    ; ResultSet rs = pstmt.executeQuery())
    {
        // give the ResultSet to the parser to process it before closing the PreparedStatement
        result = parser.accept(rs);
    }

    return result;
}

并解析结果:

public void callingMethod()
{
    ArrayList<String> result = insertRow(conn, "MY_QUERY", this::parseResultSet);
}

private ArrayList<String> parseResultSet(ResultSet resultSet) throws IOException
{
    ArrayList<String> values = new ArrayList<>();
    while (resultSet.next())
    {
        values.add(resultSet.getString("MEMBER_NAME"));
    }

    return values;
}

【讨论】:

  • 小心,许多 ResultSet 操作抛出 SQLException,Consumer&lt;T&gt; 不允许
  • 是的,刚刚在您的回答中看到了这一点:p
  • 感谢您的友好回答。这是我第一次看到消费者界面。为了使用&引用你的答案,我需要研究它^^;
  • 稍微扩展了我的示例 ;)
【解决方案3】:

您可以使用CachedRowSet

RowSetFactory factory = RowSetProvider.newFactory();
CachedRowSet rowset = factory.createCachedRowSet();
rowset .setUsername(username);
rowset .setPassword(password);
rowset .setUrl("jdbc:mySubprotocol:mySubname"); // or setDataSource() 
rowset .setCommand("select * from table");
rowset.execute();  // now you have populate data

有两个好处

  1. 不需要prepareStatement
  2. 关闭连接或准备语句比较您的方法没有问题

【讨论】:

    猜你喜欢
    • 2015-08-11
    • 2012-06-14
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2017-09-30
    相关资源
    最近更新 更多