3

I made a static method for executing the queries like this below

(this is in ServerProcess class)

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

and trying to get & use the resultset from here

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

But, as far as I know, once statement(or preparedstatement) closed, resultset would be bound to get closed as a knock-on consequences.

I would like to use it in this way somehow, but I can't figure out how to do it. Is there any possible ways to get information set after the statement closed ?

Guieen
  • 33
  • 3

3 Answers3

1

No, you can't receive the ResultSet or read anything from it when the parent PreparedStatement is already closed.

What you can do is to work with a Consumer which reads the ResultSet before you close the PreparedStatement and then returns any Business-Object you need:

The Consumer-Interface:

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

The Method now returns what the parser returns, but closes everything properly:

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

And parsing the 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;
}
Felix
  • 2,256
  • 2
  • 15
  • 35
1

Ideally you would never expose a ResultSet like that at all, it's a very mutable/stated object. However if you want to provide it, and still close it, you can use it via a lambda function:

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

Of course, you can make various methods like this, and I've actually done abstraction like that myself for personal projects across different RDBMSes.

Rogue
  • 11,105
  • 5
  • 45
  • 71
  • Thank you for your kind answer. the term 'lambda' looks difficult and makes me remind physics and mathematics :) I'll try it on today ! – Guieen Jun 10 '17 at 05:07
  • here a lambda is essentially an "anonymous method" (like anonymous classes). It's similar to the mathematics definition only in that it represents a function (but not physics, since that's wavelength) – Rogue Jun 10 '17 at 05:09
0

You can use 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

There are two advantages

  1. Don't need prepareStatement
  2. No problem to closing your connection or prepare statement comparing your method
cela
  • 2,352
  • 3
  • 21
  • 43
Boris Fain
  • 11
  • 2