Creating multiple instances of preparedstatement - java

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?

Related

JDBC: Do I Need to Reset fetchSize on a Statement That is Guaranteed to be Closed?

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)

log unclosed PreparedStatement using c3p0

Using c3p0 I can log unclosed Connection by setting properties debugUnreturnedConnectionStackTraces and
unreturnedConnectionTimeout. I wonder if is there any way to find out unclosed PreparedStatement because today I found a code as below:
...
ps=dbConnection.prepareStatement(qry);
rs=ps.executeQuery();
if(!rsCandItem.next())//to check Result Set has rows
{
rs.close();
qry = "SELECT * FROM TABLE1";
ps=dbConnection.prepareStatement(qry); //same PreparedStatement object is used without closing previous instance
rs=ps.executeQuery();
}
...
I guess using same PreparedStatement object (ps) without closing it is wrong/bad practice, correct me if I am wrong. So I want to log using c3p0 (or by any other way) unclosed PreparedStatement. Is there any way?
Unless the driver is broken, closing a Connection should also close associated statements and ResultSets. As you said, it is bad practice to not close them even if in particular cases they might not cause problems.
Since connection pools deal with Connections (and they're the ones that will leak resources), it's unlikely that there are settings for observing anything else.

java jdbc no operations allowed

I am getting a No operations allowed after statement closed. - very obvious and also self explanatory
as to what is going on with my code. In any case I am wondering how I can do this in a cleaner way
public class BaseClass {
Connection con;
Statement st;
protected void establishDBConnection() throws ClassNotFoundException,
SQLException {
Class.forName("com.mysql.jdbc.Driver");
String cString = "....";
con = DriverManager.getConnection(cString, user, password);
st = con.createStatement();
}
public BaseClass() {
try {
createDBConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public ClassB extends BaseClass {
public ClassB() {
super();
}
public void doSomething() {
try {
String q = "select * from my_table";
String moreQuery = "update my_table ...."
String anotherQuery = "do something fancy..."
rs = st.executeQuery(q);
while (rs.next()) {
st.executeUpdate(moreQuery);
st.executeUpdate(anotherQuery);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error in getAllAssociatesOfMra: " + e);
}
}
}
Currently my code is throwing a com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after statement closed.
The exception is obvious as to what is going on but I was wondering how I can go about handling the close in the BaseClass.
Update
I am aware that there a couple of related questions like mine. The only problem with those questions is that everything is done in the main class. Consider this to be kind of design/abstraction question
Your design is not good. You should be getting the connection, preferably from a connection pool, creating the statements in the beginning of your doSomething() method (for example calling the superclass method), and then closing the Statements and ResultSets when you've done "something".
Before you can make a good design you have to understand what you're trying to accomplish. So I want to establish some goals for this, then look at how the design meets those goals. In order to get the goals for this, let's go over how database connections work.
A database is a separate process, it can be on the same machine or on a different machine where it's accessed over the network. Network connections can go stale due to transient conditions, database downtime, etc. Even if the database is on the same machine and the network is not an issue, it's still bad form to have your application dependent on the state of a separate process with no way to recover, it means that if the database goes down the application can't recover by itself, you have to restart it.
Some properties of connections:
They take a while to get initialized, long enough you wouldn't want to create a new one for every user request. (This will not be nearly as big an issue if the database is on the same machine.)
There is a limited number of them, you don't want one user request to take more than necessary because that will limit the number of other users who can connect concurrently.
There's a commit method on your database connection object that lets you group your operations into transactions, so that a) your queries have a consistent view of the data, and b) the operations get applied in an all-or-nothing manner (if an operation fails you don't have half-done junk cluttering up the database that you have to undo). Currently your connections are in autocommit mode, which means each operation is committed separately (and you can't group operations together).
They're synchronized so only one thread at a time can use them. That way multiple users can't corrupt each others' work, but if you have only one connection your application won't scale since every user is waiting in line for the connection.
From all this we can derive some goals for the design. One is that we want to be able to reinitialize database connections that can go bad, we want to have multiple ones available so everybody's not waiting on the same one, and we want to associate a connection with a user request so that we can group the operations for a given user into transactions.
It's hard to tell what your posted code does exactly because it depends on the scope of the objects, which the question leaves unspecified. If these objects are created per-user-request then you will get a new connection every time, which solves the staleness issue, but may be slow. Having a different connection for every table can make the slowness worse, limits the application's concurrency unnecessarily, and also doesn't allow for transactions that group operations on different tables, because you don't have a common connection object to call commit on. How connections get closed is not apparent; it would be wasteful for them to get abandoned to timeout.
A commonly used alternative approach would be to pool the database connections (where the pool can test database connections and replace stale ones) and hand them out to user requests, returning them to the pool when the request is done with them (the pool can wrap a connection in an object where calling close on it returns it to the pool). In the meantime the user thread can execute operations on the connection, create its own statements and close them on the way out, and commit the results.
Spring has a well-thought out way of handling this situation which follows the approach described above (except with a lot more functionality). Some people dislike frameworks for overcomplicating things, but I recommend at least looking at Spring examples. That way you are aware of an alternative viable approach to organizing your code and you can improve your own design.
If I understand your question and objective, you will need to create multiple Statement objects in doSomething(), and you need to clean up your Statements and ResultSet in a finally block with something like -
Statement st = con.createStatement();
String q = "select * from my_table";
String moreQuery = "update my_table ....";
String anotherQuery = "do something fancy...";
ResultSet rs = st.executeQuery(q);
try {
while (rs.next()) {
Statement stmt = null;
try {
stmt = con.createStatement();
stmt.executeUpdate(moreQuery);
} finally {
if (stmt != null) {
stmt.close();
}
}
try {
stmt = con.createStatement();
stmt.executeUpdate(anotherQuery);
} finally {
if (stmt != null) {
stmt.close();
}
}
}
} finally {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
}
I suggest few things:
Use connection pool design
To prevent statement close, you can use finally block to close them
Since you have a query after another query, use transaction (commit/rollback) to prevent things "half done"

Does reusing a Statement and Resultset release resources from its previous usage? Or do I have to explicitly close them before reuse?

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.

When is ResultSet closed?

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.

Categories