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.
Related
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.
I am new to jdbc programming. I am creating instance of PreparedStatement multiple times and assigning it to same reference variable. Do I need to close the first instance of PreparedStatement prior to creating second instance of PreparedStatement?
oPrepStmt = oRoot.con.prepareStatement(strSql);
if (strProviderType.length() > 0) {
strSql += " and users.usertype IN (?)";
// DO I need to close prepare statement, before creating another instance of preparestatement and assigning to same reference variable.
// i.e. oPrepStmt.close();
oPrepStmt = oRoot.con.prepareStatement(strSql);
oPrepStmt.setString(2,strProviderType);
}
oPrepStmt.setInt(1,oRoot.getTrUserId());
Does the unclosed first instance of preparedstatement causes resource leaks?
JDBC statements implement AutoCloseable and therefore indicate that should explicitly be closed when no longer needed.
An object that may hold resources (such as file or socket handles)
until it is closed. The close() method of an AutoCloseable object is
called automatically when exiting a try-with-resources block for which
the object has been declared in the resource specification header.
This construction ensures prompt release, avoiding resource exhaustion
exceptions and errors that may otherwise occur.
So as suggested by the Javadoc use a try-with-resources statement:
try (PreparedStatement pstmt = oRoot.con.prepareStatement(strSql)) {
... run sql commands ...
}
In your example you create a statement and discard it for some cases. Better to avoid this and write like:
boolean checkUserType = strProviderType.length();
try (PreparedStatement pstmt = oRoot.con.prepareStatement(checkUserType ? strSql : strSql + " and users.usertype IN (?)") {
oPrepStmt.setInt(1,oRoot.getTrUserId());
if (checkUserType)
oPrepStmt.setString(2,strProviderType);
...
}
You should always close a statement when you are done with it. In some databases/JDBC drivers, a statement also has a serverside handle. Not closing the statement will leave that handle open on the server, causing unnecessary resource consumption (mostly memory, but it might lock certain metadata objects).
On top of that on the driver side not closing the statement could also have additional resource consumption (memory, listeners to connection events, etc). Closing as soon as possible is therefor advisable.
A driver will likely deallocate this eventually, either through a finalizer, or when you close the connection, but it is not a good idea to rely on that (eg connections in a connection pool do not always correctly close statements when they are returned to the pool, etc).
Now as to your specific problem, you should modify your code to something like:
if (strProviderType.length() > 0) {
strSql += " and users.usertype IN (?)";
}
try (PreparedStatement oPrepStmt = oRoot.con.prepareStatement(strSql)) {
oPrepStmt.setInt(1,oRoot.getTrUserId());
if (strProviderType.length() > 0) {
oPrepStmt.setString(2, strProviderType);
}
oPrepStmt.execute(); // or executeQuery or executeUpdate
}
I also included a try-with-resources to ensure the statement is closed as soon as possible.
BTW, likely your use of IN(?) is not going to work like this on most (all?) databases. See PreparedStatement IN clause alternatives?
Following an example in a book I am querying a table by using setFetchSize(). The book mentions to reset setAutoCommit() and setFetchSize() (the book doesn't close statement and connection in its example, so my snippet differs).
val connection = db.getConnection()
val statement = connection.prepareStatement(sql)
connection.setAutoCommit(false)
statement.setFetchSize(25)
try {
...
} finally {
statement.setFetchSize(0) // Do I need to call it if I close the stmt?
connection.setAutoCommit(true)
statement.close()
connection.close()
}
Resetting auto commit makes sense to me, because I guess after close() the connection object might be reused in a connection-pool at a later point.
However, I am curious if I need to reset the fetch size in that case. The Javadoc for connection.prepareStatement() in java.sql.Connection states:
#return a new default PreparedStatement object containing the pre-compiled SQL statement
Am I right that when closing statement I wouldn't need to reset the fetch size by calling setFetchSize(0) in the finally block?
Once a Statement is closed, it cannot be reused. There's no harm per se in resetting the fetchSize, but it doesn't serve any useful purpose.
If you close the statement you can't reuse it so anything you do on it right before or after closing would'nt change a thing.Same for the connection once you closed it you can't reuse it.(to the best of my knowledge)
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
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.