As far as I understood, closing the connection objects in finally block is the best practice. However, if rs.close() / ps.close() throws an exception at the finally block, it won't execute the conn.close(). Therefore I used to close connections at two positions (as in sample provided), once directly after use, and secondly additionally in a finally-block using a check for null. But some consider block 1 as redundant code. Is it really redundant or is there proper way to address this issue without closing the connection in two places?
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection(); // geting the connection object
ps = connection.prepareStatement(INSERT_QUERY);
rs = ps.executeQuery();
// some logic here ...
// ---- block 1 ----
ps.close()
ps = null;
rs.close();
rs = null;
conn.close();
conn = null;
// ---- end block 1 ----
} catch (SQLException e) {
// exception handling ...
} finally {
closeQuietly(conn, ps, rs);
}
private void closeQuietly(Connection connection, PreparedStatement ps, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {}
}
}
is there proper way to address this issue without closing the connection in two places?
Yes:
try (Connection conn = dataSource.getConnection(); // geting the connection object
Prepared Statement ps = connection.prepareStatement(INSERT_QUERY);
ResultSet rs = ps.executeQuery();) {
// ...
}
This is the 'try-with-resources' syntax. Everything declared inside the () after the try is guaranteed to be closed.
Yes, it would be called twice if everything goes fine with your code. That's the reason, people prefer to close any sort of connections (jdbc, stream etc) in the finally block.
As you know, The finally block gets executed whether program executed correctly or not.
So, I would recommend that you should not closing code after the use.
Jitendra
Block 1 is indeed redundant, as closeQuietly will always run due to the finally block.
closeQuietly does the right thing:
As each resource is surrounded by its own try-catch block, the code to cleanup the connection will run even if the block closing the statement or resultset throw exceptions: Those exceptions will be caught and ignored by their try-catch blocks.
Related
I get an exception that the database is locked and I try to close connection and statement, but here is the problem unreachable statement in try block.
public static ResultSet getData (String query){
try {
Connection conn = ConnectionProvider.connect();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
return rs;
try {
conn.close();
st.close();
rs.close();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
return null;
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
System.out.println(e);
return null;
}
Everything you do after the first return statement in the outer try block can never be reached. The second try block will never be executed, therefore you have some unreachable code here.
I think what you want to do is this:
try {
Connection conn = ConnectionProvider.connect();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
try {
conn.close();
st.close();
rs.close();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
return null;
}
return rs;
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
System.out.println(e);
return null;
}
Although I will say that this may just not be the correct place to use the try-catch. Maybe what you should do here is throw the possible exceptions back to whoever calls this method instead - usually nested try-catch blocks are very rarely actually used/needed in this way. Also if you encounter an exception, you just return null, instead of handling what this means for the rest of your application.
What you could also try is, assuming that at this point your query was successful:
try {
Connection conn = ConnectionProvider.connect();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
try {
conn.close();
st.close();
rs.close();
} catch (Exception e) {
throw e;
} finally {
return rs;
}
} catch (Exception e) {
throw e;
}
Though for this approach you should really think about what you need to happen in each error case.
As an additional side note, even though I'm aware that many people ignore this:
Always try to use the proper class for the Exceptions you expect in a catch-block, and if it's only for readabilities sake.
There are several things to improve in the piece of code you post.
First, you need to close the resources (Connection, Statement and ResultSet) in reverse order with respect to the opening order. So, first you should close the ResultSet, second the Statement, and finally the Connection.
Closing in the order you are doing might cause problems when closing Statement / ResultSet with the Connection already closed.
By other hand, starting in Java 7, you have the try-with-resources construct, that closes resources for you. You can take a look at The try-with-resources Statement docs.
Should I initialize Statement and ResultSet in try-with-resources Statement or just initialize in try block and close Statement and ResultSet in finally block.
I need to understand the best way to implement this according to the best practices
try-with-resources Statement
try(Connection connection = DriverManager.getConnection("url");
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("query")){
} catch (SQLException e) {
e.printStackTrace();
}
or try-catch with finally
Statement st = null;
ResultSet rs = null;
try(Connection connection = DriverManager.getConnection("url"))
{
st = connection.createStatement();
rs = st.executeQuery("query");
} catch (SQLException e) {
e.printStackTrace();
}
finally {
try {
rs.close();
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
I believe that most of the time less code is more clean code.Secondly readability does matter if you are working with a team and your team member can not read your code properly than it's definitely your fault.
In first case its look quite simple and easily understandable for the programmer who have worked with Java7 and removes the boiler plate code of closing the resources.In the second case you first initialized with null and have finally block with try-close-catch session.It is always better to go with the clean code which is the first one and note one more thing,
In a try-with-resources statement, any catch or finally block is run
after the resources declared have been closed.
Problem with try-with-resource is you can not use the resources out of the scope of try it will be limited to try block while that's not the case in your second part.
Will try-with-resources close all opened resources if exception happens?
private void insertUserInAccessTable(int user_id) throws SQLException {
final String sql = "bla bla";
try( Connection con = ...; PreparedStatement ps = ... ) {
...
if(i==0) throw new SQLException();
}
}
It will be closed even if it will throw an exception.
it will be closed regardless of whether the try statement completes
normally or abruptly
Reference:
http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Yes, but not ones that were initialized outside of the try block or inside its body (after the resource declarations).
// This connection is initialized beforehand and will not be
// closed automatically by try-with-resources
Connection conn = // ...
// The statement WILL always be closed, exception or not, before exiting the try block
try (Statement stmt = conn.createStatement())
{
// This result set will NOT be closed (directly) by try-with-resources
ResultSet rs = stmt.executeQuery(/*...*/);
}
* When try-with-resources closes the Statement, JDBC says the statement should close the ResultSet it created. So it may get closed, but only because of the JDBC contract and not because of try-with-resources.
Should I close the statement before the connection? And the resultset before the statement?
Or is it all the other way around?
Connection conn = null;
Statement st = null;
Resultset rs = null;
try {
// Do stuff
} catch (SQLException e) {
// Do stuff
}
finally {
if (rs != null) rs.close();
if (st != null) st.close();
if (conn != null) conn.close();
}
Or
Connection conn = null;
Statement st = null;
Resultset rs = null;
try {
// Do stuff
} catch (SQLException e) {
// Do stuff
}
finally {
if (conn != null) conn.close();
if (st != null) st.close();
if (rs != null) rs.close();
}
Close the result set, then the statement, then the connection.
In other words, close everything down on a last-in-first-out basis.
You should close the resources in the reverse of the order you opened (as if these resources are on a stack).
With Java 7 try-with-resources, the ideal way is:
try (
Connection conn = somethingThatGetsAConnection();
Statement st = conn.createStatement();
Resultset rs = st.executeQuery("SELECT something");
) {
// Do stuff
} catch (SQLException e) {
// Do stuff
}
And Java will take care of it for you, and it will close the resource in the reverse order. See also the Oracle tutorial on try-with-resources:
Note that the 'close' methods of resources are called in the opposite order of their creation.
You can find a more in-depth look at try-with-resources in the article Better Resource Management with Java SE 7: Beyond Syntactic Sugar
The Java Language Specification for Java 7 mentions in section 14.20.3:
Resources are initialized in left-to-right order. If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by the try-with-resources statement are closed. If all resources initialize successfully, the try block executes as normal and then all non-null resources of the try-with-resources statement are closed.
Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources.
This can also be seen as a clear indication that the Java language designers consider closing resources in the reverse order they where allocated the norm.
ResultSet, Statement and then the Connection. The golden rule to JDBC connections and statements is to close in the reverse order of initiation or opening. In addition, the ResultSet is dependant on the execution of the Statement and the Statement is dependant on the Connection instance. Hence, the closing should occur in that order (ResultSet, Statement, Connection).
The first example is the right way. The problem with any other order is that closing a Statement will automatically close any underlying ResultSet as well (and same may happen for a Connection) - so you need to close the one lowest in the hierarchy first.
The close() methods may throw a SQLException, as #aubin pointed out. One easy solution to this problem is to use DBUtils closeQuietly() method for closing them - then you don't even need to null-check!
To solve this with minimal effort, try using Java 7's new A.R.M. (Automatic Resource Management) Blocks, also known as Try-With-Resources.
try (Connection conn = null, Statement st = null, ResultSet rs = null){
// Do stuff
} catch (SQLException e) {
// Do stuff
}
No ugly Finally or worrying about proper order, Java takes care of it for you.
Some more info regarding ARM/Try-With-Resources Blocks: http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Conclusion: the order does not really matter as long as you close them individually.
From the official API specification on close() on class Connection, Statement and ResultSet:
For already closed resources, close() is a no-op:
Calling the method close on a Connection object that is already closed is a no-op.
Calling the method close on a Statement object that is already closed has no effect.
Calling the method close on a ResultSet object that is already closed is a no-op.
Closing a resource of "higher order" closes their "derived" resources:
[Connection.close()] Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be automatically reeased.
[Statement.close()] Note:When a Statement object is closed, its current ResultSet object, if one exists, is also closed.
You can try the following code to see if closing Connection also closes the other two resources:
// url, username, password and sql pre-defined
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try
{
conn = DriverManager.getConnection(url, username, password);
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
}
catch (SQLException e) { e.printStackTrace(); }
finally
{
if (conn != null)
{
System.out.println("conn is not null and I'm about to close it");
try
{
conn.close();
System.out.println(stmt != null && stmt.isClosed() ?
"stmt is also closed" : "stmt is alive");
System.out.println(rs != null && rs.isClosed() ?
"rs is also closed" : "rs is alive");
}
catch (SQLException e) { e.printStackTrace(); }
}
}
Hence, say if we close them in this FIFO order: Connection > Statement > ResultSet:
finally
{
if (conn != null)
{
try { conn.close(); }
catch (SQLException e) { e.printStackTrace(); }
}
if (stmt != null)
{
try { stmt.close(); }
catch (SQLException e) { e.printStackTrace(); }
}
if (rs != null)
{
try { rs.close(); }
catch (SQLException e) { e.printStackTrace(); }
}
}
If a "higher order" resource is successfully closed, its "derived" resources should've been closed as well
Calling close() on these already closed resources is a no-op but is fine as no exceptions are thrown
If failed to be closed, its "derived" resources still have a chance to be closed
And you can also tell the similiar story for any other arrangements.
Does use of PreparedStatements and ResultSets creates a "new database instance" everytime they are used?
Or, whith other words, if I use a PreparedStatement and a ResultSet, should I close them after every use or once I finish?
Example:
while (...){
p = connection.prepareStatement(...);
r = p.executeQuery();
while (r.next()) {
....
}
}
// We close at the end. Or there are any other p and r still opened...?
p.close();
r.close();
OR
while (...){
p = connection.prepareStatement(...);
r = p.executeQuery();
while (r.next()) {
....
}
p.close();
r.close();
}
NOTE: Of course I would use try and close properly, this is just an example.
You should close every one you open. When you create a prepared statement or result set the database allocates resources for those, and closing them tells the database to free those resources (it's likely the database will reallocate these resources eventually after a timeout period, but calling close lets the database know it can go ahead and clean up). Your second example is better, except I'd close the result set before the prepared statement.
So with try blocks included it would look like:
while (...){
PreparedStatement p = connection.prepareStatement(...);
try {
ResultSet r = p.executeQuery();
try {
while (r.next()) {
....
}
} finally {
try {
r.close();
} catch (SQLException e) {
// log this or something -- prevent these from masking original exception
}
}
}
finally {
try {
p.close();
} catch (SQLException e) {
// log this or something -- prevent these from masking original exception
}
}
}
Catching the exceptions from the close is ugly, but if you have an exception thrown during execution of the prepared statement, or during traversal of the result set, you want to make sure that you see it, and not an exception thrown when closing the prepared statement or result set (which is due to some network glitch you can't do anything about anyway).
Also be aware that using try-with-resources will work, except that if you have a case where the database operation succeeds but calling close results in an exception then the exception will get thrown.
I recommend people use the spring-jdbc library (which handles closing everything for you) instead of cranking out iffy or verbose jdbc by hand.
The first way is better.
However, you should know that you can re-use prepared statements (hence the name "prepared") if the SQL you are using is the same each time. For example:
//Note: try/catch/finally blocks removed for brevity
p = connection.prepareStatement(...);
while (...){
r = p.executeQuery();
while (r.next()) {
....
}
r.close();
}
p.close();