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.
Related
Useful piece of code for Hive JDBC:
Connection con = null;
Statement stmt = null
try {
Class.forName("org.apache.hive.jdbc.HiveDriver");
con = DriverManager.getConnection(connectionUri, userName, password);
stmt = con.createStatement();
stmt.executeUpdate(query);
} catch (ClassNotFoundException cex) {
cex.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I want to remove try - catch in finally block.
So I tried The try-with-resources Statement.
try (Class.forName("org.apache.hive.jdbc.HiveDriver");
Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement();){
stmt.executeUpdate(query);
} catch (ClassNotFoundException cex) {
cex.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
I think this is not the right way.
Class.forName("org.apache.hive.jdbc.HiveDriver") should not be in try. Should I make a separate try-catch for this?
try {
Class.forName("org.apache.hive.jdbc.HiveDriver");
} catch (ClassNotFoundException cex) {
cex.printStackTrace();
}
try (Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement();){
stmt.executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
Is this right way or am I missing any thing?
The idea behind try-with-ressource is to close an AutoCloseable class.
So every usage of a class which should be closed after using it (a Ressource) can be used with try-with-ressource (like Connection for example). You don't have to take care of closing it manually (in an finally block for example).
So yes, your idea is right:
try/catch for Class.forName("org.apache.hive.jdbc.HiveDriver"); - because this is not AutoCloseable
try-with-ressource for Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement();- because Connection and Statement implement AutoCloseable
Reference:
https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html
When you're using Java 6 or better and the Apache Hive JDBC driver is JDBC 4 compliant or better* then you do not need the Class.forName("org.apache.hive.jdbc.HiveDriver") stuff at all.
Therefore you can just remove the entire try/catch block from your second solution and you're good to go with just:
try (Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement()) {
stmt.executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
* Which is the case for version 1.2.0 or newer of the Hive JDBC driver
I'm curious about best practices when it comes to database interaction. I've been using a pattern that I believe handles making sure all of the appropriate objects are closed when I'm done with them. However, a coworker recently refactored my code with a comment along the lines of, "making sure we always close database objects". I need to know if one pattern is "better" than the other for some reason. Is the pattern that I've been using wrong somehow? Does one pattern have advantages over the other?
The pattern that I've been following:
public void doStuff() {
try {
final Connection connection = this.getConnection();
try {
final PreparedStatement ps = connection.prepareStatement("SELECT COLA, COLB FROM TBL WHERE COLC = ?");
try {
ps.setString(1, "asdf");
final ResultSet rs = ps.executeQuery();
try {
// get data from rs
} finally {
rs.close();
}
} finally {
ps.close();
}
} finally {
connection.close();
}
} catch (SQLException e) {
// do something with the error
}
}
The pattern that my coworker modifed my code to:
public void doStuff() {
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = this.getConnection();
ps = connection.prepareStatement("SELECT COLA, COLB FROM TBL WHERE COLC = ?");
ps.setString(1, "asdf");
rs = ps.executeQuery();
// get data from rs
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// do something with the error
}
}
if (ps!= null) {
try {
ps.close();
} catch (SQLException e) {
// do something with the error
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// do something with the error
}
}
}
}
If you're using Java 6 or prior, then use the latter because it's easier to read and maintain. Note that the latter can be improved with some refactoring to handle the cumbersome try-catch for every call to close method.
If you're using Java 7 or higher, then use try-with-resources:
try (Connection con = ...;
PreparedStatement pstmt = ...) {
pstmt.setXyz(...);
ResultSet rs = pstmt.executeQuery();
//read data from resultset
//and then close it
rs.close();
} catch (Exception e) {
//handle the exception properly...
}
In case you want to make sure about closing the ResultSet, you may use a nested try-with-resources:
try (Connection con = ...;
PreparedStatement pstmt = ...) {
pstmt.setXyz(...);
try(ResultSet rs = pstmt.executeQuery()) {
//read data from resultset
}
} catch (Exception e) {
//handle the exception properly...
}
The latter is easier to read; deep nesting is hard to reason about.
I prefer safe wrappers around closeables, e.g., they do nothing if the closeable is null. This also makes the mainline code easier to read.
Luigi's answer makes the most sense from Java 7 on, of course.
It's often simpler and cleaner to abstract the closure of your database resources to a dedicated manager object, which will contain any NPE's and such that might be thrown.
A pretty well written one exists as part of the open source project, OpenFire:
https://github.com/igniterealtime/Openfire/blob/master/src/java/org/jivesoftware/database/DbConnectionManager.java#L243
Sample helper method from this DbConnectionManager:
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
}
}
So in your finally block you just pass your resources back into your manager, and it handles the ugly logic to test for nulls and catch exceptions, etc.
Like:
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
ps = con.prepareStatement(yourStatement);
rs = ps.executeQuery();
if (rs != null) {
while (rs.next()) {
// do stuff
}
}
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
} finally {
DbConnectionManager.closeConnection(rs, ps, con);
}
Simulating Go's defer statement :D
try(Defer defer = new Defer())
{
Connection connection = ...;
defer.add( connection::close );
....
Path tmpFile = ...;
defer.add( ()->Files.delete(tmpFile) );
....
} // Defer.close() => executing registered actions, from last to first
How Defer is implemented is left as an exercise to readers:)
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?
There are many steps involved in executing one SQL statement in Java:
Create connection
Create statement
Execute statement, create resultset
Close resultset
Close statement
Close connection
At each of these steps SQLException can be thrown. If we to handle all exception and release all the resources correctly, the code will will look like this with 4 levels of TRY stacked on the top of each other.
try {
Connection connection = dataSource.getConnection();
try {
PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM myTable");
try {
ResultSet result = statement.executeQuery();
try {
if (result.next()) {
Integer theOne = result.getInt(1);
}
}
finally {
result.close();
}
}
finally {
statement.close();
}
}
finally {
connection.close();
}
}
catch (SQLException e) {
// Handle exception
}
Can you propose a better (shorter) way to execute a statement while still release all the consumed resources?
If you are using Java 7, the try with resources statement will shorten this quite a bit, and make it more maintainable:
try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(queryString); ResultSet rs = ps.execute()) {
} catch (SQLException e) {
//Log the error somehow
}
Note that closing the connection closes all associated Statements and ResultSets.
Check out Apache Commons DbUtils, and in particular the closeQuietly() method. It will handle the connection/statement/result set closing correctly, including the cases where one or more are null.
An alternative is Spring JdbcTemplate, which abstracts a lot of work away from you, and you handle your database queries in a much more functional fashion. You simply provide a class as a callback to be called on for every row of a ResultSet. It'll handle iteration, exception handling and the correct closing of resources.
I create a utility class with static methods I can call:
package persistence;
// add imports.
public final class DatabaseUtils {
// similar for the others Connection and Statement
public static void close(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (Exception e) {
LOGGER.error("Failed to close ResultSet", e);
}
}
}
So your code would be:
Integer theOne = null;
Connection connection = null;
PreparedStatement statment = null;
ResultSet result = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
while (result.next()) {
theOne = result.getInt(1);
}
} catch (SQLException e) {
// do something
} finally {
DatabaseUtils.close(result);
DatabaseUtils.close(statement);
DatabaseUtils.close(connection);
}
return theOne;
I'd recommend instantiating the Connection outside this method and passing it in. You can handle transactions better that way.
Connection connection = null;
PreparedStatement statement = null;
ResultSet result = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
if (result.next()) {
Integer theOne = result.getInt(1);
}
}
catch (SQLException e) { /* log error */ }
finally {
if (result != null) try { result.close(); } catch (Exception e) {/*log error or ignore*/}
if (statement != null) try { statement.close(); } catch (Exception e) {/*log error or ignore*/}
if (connection != null) try { connection.close(); } catch (Exception e) {/*log error or ignore*/}
}
Just close the Connection, this releases all resources*. You don't need to close Statement and ResultSet.
*just make sure you don't have any active transactions.
Your code can be shortened and written in this way...
Connection connection = dataSource.getConnection();
PreparedStatement statement = null;
ResultSet result = null;
try {
statement= connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
if (result.next()) {
Integer theOne = result.getInt(1);
}
} catch (SQLException e) {
// Handle exception
} finally {
if(result != null) result.close();
if(statement != null) statement.close();
if(connection != null) connection.close();
}
When using a PreparedStatement in JDBC, should I close the PreparedStatement first or the Connection first? I just saw a code sample in which the Connection is closed first, but it seems to me more logical to close the PreparedStatement first.
Is there a standard, accepted way to do this? Does it matter? Does closing the Connection also cause the PreparedStatement to be closed, since the PreparedStatement is directly related to the Connection object?
The statement. I would expect you to close (in order)
the result set
the statement
the connection
(and check for nulls along the way!)
i.e. close in reverse order to the opening sequence.
If you use Spring JdbcTemplate (or similar) then that will look after this for you. Alternatively you can use Apache Commons DbUtils and DbUtils.close() or DbUtils.closeQuietly().
The following procedures should be done (in order)
The ResultSet
The PreparedStatement
The Connection.
Also, it's advisable to close all JDBC related objects in the finally close to guarantee closure.
//Do the following when dealing with JDBC. This is how I've implemented my JDBC transactions through DAO....
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = ....
ps = conn.prepareStatement(...);
//Populate PreparedStatement
rs = ps.executeQuery();
} catch (/*All relevant exceptions such as SQLException*/Exception e) {
logger.error("Damn, stupid exception: " , e);
} finally {
if (rs != null) {
try {
rs.close();
rs = null;
} catch (SQLException e) {
logger.error(e.getMessage(), e.fillInStackTrace());
}
}
if (ps != null) {
try {
ps.close();
ps = null;
} catch (SQLException e) {
logger.error(e.getMessage(), e.fillInStackTrace());
}
}
try {
if (conn!= null && !conn.isClosed()){
if (!conn.getAutoCommit()) {
conn.commit();
conn.setAutoCommit(true);
}
conn.close();
conn= null;
}
} catch (SQLException sqle) {
logger.error(sqle.getMessage(), sqle.fillInStackTrace());
}
}
You can see I've checked if my objects are null and for connection, check first if the connection is not autocommited. Many people fail to check it and realise that the transaction hasn't been committed to DB.