This question already has answers here:
When is ResultSet closed?
(3 answers)
Closed 5 years ago.
I have a function which returns a resultset which is associted to a prepared statement.i am closing the prepared statement in the finally block.
it automatically closes the resultset also which i need to return.
what is an alternative way for this?
My code looks like this
Resultset fnName(){
Resultset rs = null;
PreparedStatement ps = new PreparedStatement();
try{
rs = ps.execute(<query string>);
}
catch(...){...}
finally{
ps.close().
}
return rs;
}
You could have read the Javadoc (my emphasis):
void close​()
throws SQLException
Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.
Calling the method close on a Statement object that is already closed has no effect.
Note: When a Statement object is closed, its current ResultSet object, if one exists, is also closed.
Related
This question already has answers here:
Does a ResultSet load all data into memory or only when requested?
(5 answers)
Closed 6 years ago.
I have a simple Java 6 code:
Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost/db?user=u&password=p");
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM "+tabela);
while(res.next()){
byte[] fileBytes = res.getBytes(fileColumnIndex);
fos.write(fileBytes);
}
So my question is - does ResultSet load all data to some local memory at once, or does it load it by chunks on every res.next()?
Simply check the Javadoc:
https://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html
You are moving through your result from the executed SQL query, row by row, column by column (by the index or the column name)
(Don't forget to free resources when you are done with your result set).
About your question, consider as a programmer the ResultSet as the same concept to the Stream: "you can't do anything about the past, you don't know the future, you can only process the present"
According to doc of http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#close() ,
When a Statement object is closed, its current ResultSet object, if
one exists, is also closed.
But accoring to Must JDBC Resultsets and Statements be closed separately although the Connection is closed afterwards? , it is seems to be a good practice to explicitly close Connection Statement and ResultSet .
If we still need to close ResultSet, we may need to have a nested try-with-resources statement since we may probably set parameter for Statement like this:
try (Connection conn = connectionProvider.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql) {//resources of conn and pst
setPrepareStatementParameter(pstmt, kvs);//need to set parameters, so I have to put ResultSet into another try-with-resources statement
try (ResultSet res = pstmt.executeQuery()) {
..............
}
}
Question:
Does put the ResultSet into a separate try-with-resources statement worth anything since the doc states that closing Statement will close the ResultSet
Your example covers too limited a range of the interactions between Connections, Statements, and ResultSets. Consider the following:
try (Connection conn = connectionProvider.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);) {
for (int i = 0; i < kvs.length; i++) {
setPrepareStatementParameter(pstmt, kvs[i]);
// do other stuff
// Place the ResultSet in another try with resources
// to ensure the previous iteration's ResultSet
// is closed when the next iteration begins
try (ResultSet res = pstmt.executeQuery()) {
..............
}
}
}
In the above example, the PreparedStatement is parametrized and executed a kvs.length number of times within the for-loop. Imagine a case in which the parametrization process, for any reason, took a significant length of time. Note that closing the PreparedStatement would do us no good since we want to reuse the compiled SQL statement at every iteration of the for-loop. Then surely nesting the ResultSet into its own try-with-resources block---thus ensuring the prior iteration's ResultSet is closed but the PreparedStatement remains open---is a worthwhile effort.
Yes, you should close or put a try-resources for result set.
Why?
I quote what I've read from other answer that makes a lot of sense for me.
In theory closing the statement closes the result set.
In practice, some faulty JDBC driver implementations failed to do so.
Check the full answer here:
https://stackoverflow.com/a/45133734/401529
I have a snippet like this:
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM table_A");
statement.closeOnCompletion();
System.out.println(statement.isCloseOnCompletion());
rs.close();
System.out.println(statement.isClosed());
After closeOnCompletion is invoked, I expect the statement to be closed, as its result set is closed. However, it just shows "false" when checking statement.isClosed().
Did I misunderstand the jdk doc? as it says: closeOnCompletion() Specifies that this Statement will be closed when all its dependent result sets are closed.
===========================
Update:
It turns out to be my carelessness. The last statement actually returns a result of expected "true". So it's no longer an issue
Since Statement is depend on result I would suggest this
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM table_A");
rs.close();
statement.close();
System.out.println(statement.isClosed());
This is applicable if your ultimate want is to close statement, if your question is why statement is not closing even when called onexit, then better to refer javadocs.
Sample code:
aStmt = aConn.prepareStatement(aQuery);
aRset = aStmt.executeQuery(cQuery);
while (cRset.next()) {
//stuff to determine value of parm1
aStmt.setString(1, parm1);
aRset = aStmt.executeQuery();
//more stuff
}
Do I have to close aStmt and aRset after every loop inside the while statement? Or will reusing them in the succeeding loops release the memory/resources used from the previous loops?
The behavior of resultsets and (prepared) statements is explicitly documented in the Java API. I suggest that you read the actual documentation (and the JDBC spec) to get the details.
The Statement API says:
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a current ResultSet object of the statement if an open one exists.
(emphasis mine).
In your specific code, when you call aStmt.executeQuery(), the old ResultSet assigned to aRset is implicitly closed by the driver. That said, it would be better to explicitly close it yourself (or use Java 7 try-with-resources), to prevent you from forgetting to close the ResultSet in the last iteration through the loop.
Now to the PreparedStatement: When you prepare a statement (in general, implementation can vary), the query is sent to the server for compilation. On execution the parameters for that specific execution is sent to the server. Calling close() on aStmt would result in the prepared statement being deallocated on the server, that is clearly NOT what you want here as you want to re-use the statement with different values for its parameter.
So in short
Closing ResultSet is not technically necessary here (except for the last ResultSet created), but it is better to do it explicitly
You should only close the PreparedStatement when you are done with it.
Using try-with-resources is one way to remove part of the confusion on these issues, as your code will automatically release resources when it is done with it (at the end of the scope of use):
try (
ResultSet cRset = cStmt.executeQuery(cQuery);
PreparedStatement aStmt = aConn.prepareStatement(aQuery);
) {
while (cRset.next()) {
//stuff to determine value of parm1
aStmt.setString(1, parm1);
try (ResultSet aRset = aStmt.executeQuery()) {
//more stuff
}
}
}
At the end of this piece of code all JDBC resources are correctly closed (in the right order, even if exceptions occurred etc)
No, you may not close the ResultSet and Statement inside the while loop.
You have to close them after the loop.
Also if you want to reuse the PreparedStatement then you may not close it until you're ready with your processing.
Best rule is to close such resources in the same block as they're created. In your case the best thing to do is to close the resources in a finally block after catching the SQLException.
E.g.
try {
aStmt = aConn.prepareStatement(aQuery);
cRset = cStmt.executeQuery(cQuery);
while (cRset.next()) {
//stuff to determine value of parm1
aStmt.setString(1, parm1);
try {
aRset = aStmt.executeQuery();
} finally {
aRset.close();
}
//more stuff
}
} catch (SQLException ex) {
// Do error handling
} finally {
// Close Resultset
}
In Java 7 you can use try with resources.
PreparedStatement API: A SQL statement is precompiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.
But you cannot reuse a ResultSet object. When you call executeQuery on a PreparedStatement object the second time a new ResultSet is created, if you do not close the previous ResultSet you are risking to get a resource leak.
I want to know if ResultSet can be closed if I didn't close it ? I have a ResultSet is closed exception but I am sure I didn't close the ResultSet anywhere .
What I do exactly is that I use the ResultSet to perform a SELECT query then I use the same ResultSet because it's called by this method :
public Object getValueAt( int row, int column )
throws IllegalStateException {
// ensure database connection is available
if ( !dbConnection.isConnectedToDatabase() )
throw new IllegalStateException( "Not Connected to Database" );
// obtain a value at specified ResultSet row and column
try {
getResultSet().absolute( row + 1 );
return getResultSet().getObject( column + 1 );
} // end try
catch ( SQLException sqlException ) {
System.out.println("Exception from here dude");
sqlException.printStackTrace();
} // end catch
return ""; // if problems, return empty string object
} // end method getValueAt
So , another question : Is there a way to ensure the ResultSet is opened ?
Third question : Maybe the problem because I never close ResultSets .
What's the point of closing ResultSet ?
Edit : That's how statement is being created inside the constructor of a class called DBConnection:
Class.forName(driver);
// connect to database
connection = DriverManager.getConnection(url, username, password);
// create Statement to query database
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY );
//connection ok
connectedToDatabase=true;
ResultSet is created later whenever I want to execute a statement.
Directly from the docs on ResultSet.close():
Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.
...
Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results.
So, if you closed the Statement that generated your ResultSet is closed, you get that exception.
Another question's answer: you shouldn't read results from a ResultSet like that. Perform the select an read all the data you need from the ResultSet at once, close the connection and then later you can read the fetched data as much as you want. You really shouldn't have an external resource/class calling your getValueAt method, which you expect to still be connected to the database. Connection may be terminated for many other reasons, so that's not the way to go.
Third answer: answered above.
Last answer: releasing resources explicitly, without waiting for it to be closed when Statement is.
In case you have closed any of the following, your ResultSet will be closed automatically:
Statement object.
Connection object.
I am strongly suspecting the connection is being closed. It is a natural tendency to close the database connection once the query is run. While it is a good practice, but may be you are closing the connection even before you have used the ResultSet object inside your TableModel class.
I always close Connections, ResultSets and Statements in finally {} block. In such case I don't have this problem, since this block is always executed (Well, not always, but here it fits). Please refer to this post, I placed skeleton implementation that might be interesting for you.