Consider the code:
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.createStatement(myQueryString);
rs = ps.executeQuery();
// process the results...
} catch (java.sql.SQLException e) {
log.error("an error!", e);
throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
ps.close();
rs.close();
}
The above does not compile, because both PreparedStatement.close() and ResultSet.close() throw a java.sql.SQLException. So do I add a try/catch block to the finally clause? Or move the close statements into the try clause? Or just not bother calling close?
In Java 7, you should not close them explicitly, but use automatic resource management to ensure that resources are closed and exceptions are handled appropriately. Exception handling works like this:
Exception in try | Exception in close | Result
-----------------+--------------------+----------------------------------------
No | No | Continue normally
No | Yes | Throw the close() exception
Yes | No | Throw the exception from try block
Yes | Yes | Add close() exception to main exception
| | as "suppressed", throw main exception
Hopefully that makes sense. In allows pretty code, like this:
private void doEverythingInOneSillyMethod(String key)
throws MyAppException
{
try (Connection db = ds.getConnection()) {
db.setReadOnly(true);
...
try (PreparedStatement ps = db.prepareStatement(...)) {
ps.setString(1, key);
...
try (ResultSet rs = ps.executeQuery()) {
...
}
}
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
Prior to Java 7, it's best to use nested finally blocks, rather than testing references for null.
The example I'll show might look ugly with the deep nesting, but in practice, well-designed code probably isn't going to create a connection, statement, and results all in the same method; often, each level of nesting involves passing a resource to another method, which uses it as a factory for another resource. With this approach, exceptions from a close() will mask an exception from inside the try block. That can be overcome, but it results in even more messy code, and requires a custom exception class that provides the "suppressed" exception chaining present in Java 7.
Connection db = ds.getConnection();
try {
PreparedStatement ps = ...;
try {
ResultSet rs = ...
try {
...
}
finally {
rs.close();
}
}
finally {
ps.close();
}
}
finally {
db.close();
}
If you're really hand-rolling your own jdbc it definitely gets messy. The close() in the finally needs to get wrapped with its own try catch, which, at the very least, is ugly. You can't skip the close, although the resources will get cleared when the connection is closed (which might not be right away, if you're using a pool). Actually, one of the main selling points of using a framework (e.g. hibernate) to manage your db access is to manage the connection and result set handling so you don't forget to close.
You can do something simple like this, which at least hides the mess, and guarantees that you don't forget something.
public static void close(ResultSet rs, Statement ps, Connection conn)
{
if (rs!=null)
{
try
{
rs.close();
}
catch(SQLException e)
{
logger.error("The result set cannot be closed.", e);
}
}
if (ps != null)
{
try
{
ps.close();
} catch (SQLException e)
{
logger.error("The statement cannot be closed.", e);
}
}
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
logger.error("The data source connection cannot be closed.", e);
}
}
}
and then,
finally {
close(rs, ps, null);
}
For file I/O, I generally add a try/catch to the finally block. However, you must be careful not to throw any exceptions from the finally block, since they will cause the original exception (if any) to be lost.
See this article for a more specific example of database connection closing.
Don't waste your time coding low-level exception management, use an higher-level API like Spring-JDBC, or a custom wrapper around connection/statement/rs objects, to hide the messy try-catch ridden code.
Also note:
"When a Statement object is closed, its current ResultSet object, if one exists, is also closed. "
http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close()
It should be sufficient to close only the PreparedStatement in a finally, and only if it is not already closed. If you want to be really particular though, close the ResultSet FIRST, not after closing the PreparedStatement (closing it after, like some of the examples here, should actually guarantee an exception, since it is already closed).
I usually have a utility method which can close things like this, including taking care not to try to do anything with a null reference.
Usually if close() throws an exception I don't actually care, so I just log the exception and swallow it - but another alternative would be to convert it into a RuntimeException. Either way, I recommend doing it in a utility method which is easy to call, as you may well need to do this in many places.
Note that your current solution won't close the ResultSet if closing the PreparedStatement fails - it's better to use nested finally blocks.
Building on #erickson's answer, why not just do it in one try block like this?
private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
try (Connection db = ds.getConnection();
PreparedStatement ps = db.prepareStatement(...)) {
db.setReadOnly(true);
ps.setString(1, key);
ResultSet rs = ps.executeQuery()
...
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
Note that you don't need to create the ResultSet object inside the try block as ResultSet's are automatically closed when the PreparedStatement object is closed.
A ResultSet object is automatically closed when the Statement object
that generated it is closed, re-executed, or used to retrieve the next
result from a sequence of multiple results.
Reference: https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
If your are using Java 7 you can use the improvements in the exception handling mechanisms in those classes that implement AutoCloseable (i.e. PreparedStatement, Resultset)
You might also find this question interesting: Closing ResultSet in Java 7
I know this is an old question, but just in case someone is looking for the answer, java now has the try-with-resouce solution.
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
Do no omit calling close. It may cause problems.
I prefer adding try/catch block to the finally.
focus finally clause,
finally {
try {
rs.close();
ps.close();
} catch (Exception e) {
// Do something
}
}
I think you have to modify 2 points.
First, use try & catch again in fainlly clause.
Second, do rs.close() before doing ps.close().
fly1997#naver.com
Probably an old (though simple) way to do things, but it still works:
public class DatabaseTest {
private Connection conn;
private Statement st;
private ResultSet rs;
private PreparedStatement ps;
public DatabaseTest() {
// if needed
}
public String getSomethingFromDatabase(...) {
String something = null;
// code here
try {
// code here
} catch(SQLException se) {
se.printStackTrace();
} finally { // will always execute even after a return statement
closeDatabaseResources();
}
return something;
}
private void closeDatabaseResources() {
try {
if(conn != null) {
System.out.println("conn closed");
conn.close();
}
if(st != null) {
System.out.println("st closed");
st.close();
}
if(rs != null) {
System.out.println("rs closed");
rs.close();
}
if(ps != null) {
System.out.println("ps closed");
ps.close();
}
} catch(SQLException se) {
se.printStackTrace();
}
}
}
I use this..
finally
{
if (ps != null) ps.close();
if (rs != null) rs.close();
}
In the below example we are closing connection and prepared statement using try with resource. It will close connection and prepared statement.
And also we are using 2 try block as explained below
For closing connection and prepared statement
Closing result set
In future, if we have any file-related operation then we'll need to write another try with resource block
try (Connection con = ds.getConnection();
PreparedStatement ps = con.prepareStatement(sql);) {
try (ResultSet rs = ps.executeQuery();) {
while (rs.next()) {
list.add(rs.getInt("id"));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
But if we are not using try with resource then we can rewrite above login in single try catch block as below
try {
Connection con = ds.getConnection();
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
list.add(rs.getInt("id"));
}
} catch (Exception e) {
// Closing RS
// Closing PS
// Closing Connection or Customized closing connection logic
}
Question: Even if we have any custom operation while closing connection, is it possible to use a try with resource block?
Also please suggest which one better solution in that case.
Try with resources is a better solution because it uses your connections only inside the "try" block. BUT :
catch (SQLException e)
is not the same thing with :
catch (Exception e)
The (Exception e) will catch SQLException and if you said that you want to do some file related operations, will catch maybe a FileNotFoundException or IOException too so this catch is not very suggestive. In my opinion you should first read the Single Responsibility Principle and then you'll see that the best option to handle your problem is to create 2 try blocks which will handle independently the operations like this:
public static List<Integer> getAllProducts() {
List<Integer> productIds = new ArrayList<>();
try (Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement(sql);) {
try (ResultSet rs = ps.executeQuery();) {
while (rs.next()) {
productIds.add(rs.getInt("id"));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return productIds;
}
public static void writeSomething(String fileName) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
writer.write("StackOverflow");
} catch (IOException e) {
e.printStackTrace();
}
}
I've had a similar issue a couple of weeks ago. You don't need to have multiple try-with-resources, you can only have one see this.
But in your second sample of code, you don't want to close your connection and all in the catch block. You must use the finally block.
In short you can use only one try-with-resources for the "normal" stuff, and create another try-catch-finally inside the latter (or use call to a custom method) to handle and close your customs operations.
try (Connection conn = datasource.getConnection();
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery(request); ) {
while (rs.next())
{
// Do your stuff.
}
try
{
// Do your stuff.
} catch (Whatever e) {
// Handle.
} finally {
// Close your custom stuff.
}
} catch (SQLException ex) {
// throw something.
}
Hope this helps.
I'm trying to analyze a heap dump to find a memory leak for the first time. I'm opening up the heap dump using MAT and right away it's pretty clear it's one object? that is taking up almost the entire heap and it's a sql class com.mysql.cj.jdbc.ConnectionImpl.
Since sql is really used in only one part of my code it basically has to be something with this small bit of code here...
static Connection getDBconn() {
Connection conn = null;
while (conn == null) {
try {
conn = DriverManager.getConnection(serverURL, user, pass);
} catch (SQLException e) {
Logger.logError(e);
}
}
return conn;
}
static void update(String sql) {
while (currConn == null)
currConn = getDBconn();
boolean error = false;
do {
try {
currConn.createStatement().executeUpdate(sql);
} catch (SQLException e) {
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
currConn = getDBconn();
Logger.logError(e);
error = true;
}
} while (error);
}
static ResultSet query(String sql) {
while (currConn == null)
currConn = getDBconn();
ResultSet rs = null;
while (rs == null) {
try {
rs = currConn.createStatement().executeQuery(sql);
} catch (SQLException e) {
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
currConn = getDBconn();
Logger.logError(e);
}
}
return rs;
}
What this code is supposed to do is basically wrap query/update statements inside some methods to ensure that each command is always carried out eventually, even when an error comes up. My program will be running for long amounts of time with many requests, and i want to ensure it deals with all possible problems automatically without interrupting the program.
What i have written will work for about an hour or so and then i'll get a out of memory error even when i have my heap set to like 8gb which is obviously overkill. I should also note i'm not getting any sql errors so it's not even getting into the catch blocks. Clearly there is some sort of leak with this code but i'm having trouble figuring out what it could be. Any advice would be appreciated and i can provide more information on the heap dump if needed.
You are getting connection when you don't need it twice
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
--> currConn = getDBconn();
Logger.logError(e);
Just remove currConn = getDBconn() after currConn.close(); and you won't have connection leak.
Better yet, close connection on finally even if no error occurred:
try {
rs = currConn.createStatement().executeQuery(sql);
} catch (SQLException e) {
Logger.logError(e);
finally{
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
}
Also create a method to prevent code duplication and different implementation of closing connection.
I have connection provider class as bleow to return connection.
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws ClassNotFoundException, SQLException {
try (Connection connection = DriverManager
.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
) {
return connection;
}
}
}
Here is main method to call connection provider.
public void Test() {
try {
Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
But "com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed." error are always show at below line of code.
PreparedStatement ps = con.prepareStatement("");
Because, according to Oracle documentation, If use try with resources java 7 features, resources are auto close after try block even it's errors occurred or not. So even I returned the connection it's already closed.
Let me know, my usage logic is wrong?
How can I return this connection inside try with resource?
I tried many time googling for solution but does not get convenience answers for me.
Let me know your suggestion and feedback please.
What you can't do...
With a try-with-resources as you have it after you return the connection you return(d) is close(d). You can't return the connection from inside the try with resources.
What you can do...
Pass the connection (inside your try-with-resources) to a method that takes a connection. You can also use a ConnectionPool, and get the Connection when you need it (to create and execute a query).
Let me know, my usage logic is wrong?
The usage of 'try-with-resources' logic is wrong in this context, because the intention of ConnectDB() is to return a connection instance which could be actually used by the caller to send a SQL statement, but instead, the connection instance is getting auto-closed, before it could be used by the caller, because of using 'try-with-resources' construct of Java.
Quick how-to on try-with-resource and JDBC
Your ConnectionProvider's ConnectDB already declares it is throwing SQLException - so no need to catch it in here: (You should consider replacing this code with connection pool maybe)
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
}
}
Instead use try-with-resource in your test-class to clean up your code and focus on errors your SQL code
might have:
public void Test() {
try (Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("SELECT 1")) {
//Prepare your Statement
ps.setInt(1, 1);
//And another try-with-resource for the result - note the closing brace
try(ResultSet rs = ps.executeQuery()) {
while(rs.next()) {
//Handle your Result
System.out.println(rs.getString(1));
}
} // This closes try-with-resource. Exception will be rethron to be caught in outer catch!
} catch (SQLException e) {
//SQL is Broken - but only ONE catch to catch them all
e.printStackTrace();
}
}
That way you gain
Better readability for your code (no calls to close surrounded by finally and if != null)
Centralized error handling if anything in your SQL code breaks (so you can focus on functional error of "statement didn't run")
Better code quality: No need to worry about Cursors, Statements, Connections not being propery closed.
I'm trying to figure out how to rollback commits from multiple methods. I want to do something like the following (editing for brevity)
public void testMultipleMethodRollback() throws DatabaseException {
Connection conn = connect();
fakeMethodRollback1();
fakeMethodRollback2();
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
and currently all my methods are formatted like this
public void fakeMethodRollback1() throws DatabaseException {
Connection con = connect();
PreparedStatement ps = null;
ResultSet rs = null;
// insert some queries
try {
String query = "some query";
ps = conn.prepareStatement(query);
ps.executeUpdate(query);
query = "some query";
ps = conn.prepareStatement(query);
ps.executeUpdate(query);
con.commit();
} catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
throw new DatabaseException(e);
} finally {
close(rs, ps, conn);
}
}
because I want to be able to use the other methods independently, how can I do a rollback where if one method fails, the others will roll back? I fear I have my whole class setup wrong or at least wrong enough that this can't be accomplished without major work. I can't change the methods to return a connection, because half of my methods are get methods, which are already returning other data. Any ideas?