预处理语句关闭后如何获取结果集?(Java)

3
我为执行以下查询编写了一个静态方法:
(这是在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)关闭,结果集将会被关闭,这是一种连锁反应。

我想以某种方式使用它,但我无法想出如何做到。是否有可能在语句关闭后获取信息集?


2
有没有办法在 PreparedStatement 关闭后获得结果集?(Java)没有。 - Felix
假设这个帖子讨论了你的问题并提供了解决方案。 - Rajith Pemabandu
是的,我知道这听起来像无意义的话,但我只是好奇并想知道是否有一些好的想法。 - Guieen
1
提供回调函数 - 或使用Spring的JdbcTemplate - Erwin Bolwidt
3个回答

1

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

您可以使用Consumer与ResultSet一起工作,在关闭PreparedStatement之前读取ResultSet,然后返回所需的任何业务对象:

Consumer接口:

@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;
}

1
小心,许多ResultSet操作会抛出SQLException,这是Consumer<T>不允许的。 - Rogue
是的,刚看到你的回答 :p - Felix
谢谢您的友善回答。这是我第一次看到Consumer Interface。为了使用和参考您的答案,我需要学习它^^; - Guieen
稍微扩展了一下我的示例 ;) - Felix

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
});

当然,你可以像这样制作各种方法,而我自己在个人项目中跨不同的RDBMS进行了抽象

感谢您的友善回答。术语“lambda”看起来很困难,让我想起了物理和数学 :) 我会在今天尝试一下! - Guieen
这里的lambda本质上是一个“匿名方法”(类似于匿名类)。它与数学定义类似,只表示一个函数(但不是物理学中的波长)。 - Rogue

0

你可以使用 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. 不需要准备语句
  2. 与您的方法相比,关闭连接或准备语句没有问题

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接