I have query regarding fetching jdbc connection from pool in sub method.Following are two method i came across suggest me which one best to avoid connection leakage and tell if any other solution.
Method 1:
getConnection is method which return Connection.
void testMain(){
Connection conn = getConnection();
subMethod(conn)
conn.close();
}
void subMethod(connection conn){
// use jdbc connection
return;
}
Method2:
void testMain(){
Connection conn = getConnection();
subMethod()
conn.close();
}
void subMethod(){
Connection conn = getConnection();
conn.close();
return;
}
The place where you need a Connection should get the connection.
The way you ensure that no resources are "leaked" is by using java 7's try-with-resource syntax:
public String fetchSomeData() {
try (Connection conn = getConnection()) { // This line, with this syntax, will ensure that it is automatically closed in an invisible "finally" block
// Do what you need to do with the data, return it or something else
} catch (SQLException e) {
// No need to do clean up here, log the exception or do whatever you want.
}
}
You can use try-with-resource syntax on any objects that implement AutoCloseable interface. That includes Connection, Statement, and Resultset among others.
If you need to do a transaction you might want to initialize the Connection in a method, and then pass that Connection to different other methods that adds to the transaction, and then commit it. If that's the case, you can do:
public String fetchSomeDataInTransactionStyle() {
try (Connection conn = getConnection()) { // This line, with this syntax, will ensure that it is automatically closed in an invisible "finally" block
conn.setAutocommit(false);
addSomethingToTransaction(conn);
addSomethingMore(conn);
conn.commit();
} catch (SQLException e) {
// No need to do clean up here, log the exception or do whatever you want.
}
}
Related
I'm writing a transaction with Java 8. First, my code was like this.
try (Connection conn = DAOUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(addSubscriptionSql)) {
conn.setAutoCommit(false);
//do work
conn.commit();
} catch (SQLException e) {
e.printStackTrace(); //handle error
}
But since I should rollback in case of transaction failure, I had to change the code like this. Note the two try blocks.
try (Connection conn = DAOUtil.getConnection()) {
try (PreparedStatement ps = conn.prepareStatement(addSubscriptionSql)) {
conn.setAutoCommit(false);
//do work
conn.commit();
} catch (SQLException e) {
conn.rollback();
e.printStackTrace(); //handle error
}
} catch (SQLException e) {
e.printStackTrace(); //handle error
}
My question is, is there a better (I mean simpler) way of doing this? Can I achieve this with a single try block?
You can use
try(Connection conn = DAOUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(addSubscriptionSql);
AutoCloseable finish = conn::rollback) {
conn.setAutoCommit(false);
//do work
conn.commit();
}
This will always call rollback(), but after a successful completion of commit(), the rollback will become a no-op as it resets the state to that after the last successful completion of commit()…
Since AutoCloseable declares to throw Exception that will require to handle this broad exception type. It can be fixed with a custom type that might be useful in other cases as well:
interface SQLCloseable extends AutoCloseable {
#Override public void close() throws SQLException;
}
…
try(Connection conn = DAOUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(addSubscriptionSql);
SQLCloseable finish = conn::rollback) {
conn.setAutoCommit(false);
//do work
conn.commit();
}
Now, only the handling of the exception type SQLException is enforced.
If you don’t like the idea of rollback() being called unconditionally, the solution becomes less elegant:
boolean[] success = { false };
try(Connection conn = DAOUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(addSubscriptionSql);
SQLCloseable finish = () -> { if(!success[0]) conn.rollback(); }) {
conn.setAutoCommit(false);
//do work
conn.commit();
success[0] = true;
}
If you reset the auto-commit state at the end, you could use that as an indicator for the necessity of a roll-back:
try(Connection conn = DAOUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(addSubscriptionSql);
SQLCloseable finish = () -> { if(!conn.getAutoCommit()) conn.rollback(); }) {
conn.setAutoCommit(false);
//do work
conn.commit();
conn.setAutoCommit(true);
}
Can I achieve this with a single try block?
No, because your conn object will not be available in the catch block of your try-with-resources. If you want to catch an exception while executing the PreparedStatement and explicitly do a conn.rollback() then the rollback will have to happen within the try of the try-with-resources that creates the conn object (i.e., using a second nested try block for the PreparedStatement call).
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 am trying to setup a boneCP connection and I am getting the following error message:
Exception in thread "main" java.lang.ClassCastException: com.jolbox.bonecp.StatementHandle cannot be cast to com.mysql.jdbc.Statement
The connection seems to work fine but I get stopped out at the query.
Here is my code:
BoneCP connectionPool = null;
Connection connection = null;
try {
// load the database driver (make sure this is in your classpath!)
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
// setup the connection pool
BoneCPConfig config = new BoneCPConfig();
config.setJdbcUrl("jdbc:mysql://192.126.0.0:3306/"); // jdbc url specific to your database, eg jdbc:mysql://127.0.0.1/yourdb
config.setUsername("root");
config.setPassword("");
config.setMinConnectionsPerPartition(5);
config.setMaxConnectionsPerPartition(10);
config.setPartitionCount(1);
connectionPool = new BoneCP(config); // setup the connection pool
connection = connectionPool.getConnection(); // fetch a connection
if (connection != null){
System.out.println("Connection successful!");
Statement stmt = (Statement) connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1 FROM table"); // do something with the connection.
while(rs.next()){
System.out.println(rs.getString(1)); // should print out "1"'
}
}
connectionPool.shutdown(); // shutdown connection pool.
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
This is quite simple: If you use BoneCP, you do not have direct access to the objects of the underlying driver. This applies to connection pools in general, because they usually object proxies to handle resource management (eg close statements, resultsets etc when the connection is returned to the pool). This especially applies to statements as connection pools can (and usually do) also provide statement caching.
Specifically for BoneCP you should be able to get to the wrapped statement using StatementHandle.getInternalStatement() (although I am not 100% sure about that).
Although the big question is: why do you need to cast to com.mysql.jdbc.Statement, isn't the java.sql.Statement interface sufficient for you?
As I was cleaning up some code, FindBugs pointed me to a bit of JDBC code that uses Connection, CallableStatement, and ResultSet objects. Here's a snippet from that code:
CallableStatement cStmt = getConnection().prepareCall("...");
...
ResultSet rs = cStmt.executeQuery();
while ( rs.next() )
{
...
}
cStmt.close();
rs.close();
con.close();
FindBugs pointed out that these should be within a finally block. I started refactoring my code to do this and I started to wonder how to handle the code within the finally block.
It's possible that the creation of the CallableStatement of Connection objects would throw an exception, leaving my ResultSet object as null. When I try to close the ResultSet, I'd get a NullPointerException and my Connection would, in turn, never get closed. Indeed, this thread brings up the same concept and shows that wrapping your close() invocations in a null check is a good idea.
But what about other possible exceptions? According to the Java API spec, Statement.close() can throw a SQLException "if a database error occurs". So, even if my CallableStatement is not null and I can successfully call close() on it, I might still get an exception and not have a chance to close my other resources.
The only "fail safe" solution I can think of is to wrap each close() invocation in its own try/catch block, like this:
finally {
try {
cStmt.close();
} catch (Exception e) { /* Intentionally Swallow Exception */ }
try {
rs.close();
} catch (Exception e) { /* Intentionally Swallow Exception */ }
try {
con.close();
} catch (Exception e) { /* Intentionally Swallow Exception */ }
}
Boy, if that doesn't look awful. Is there a better way to go about this?
I think the best answer has already being mentioned, but I thought it could be interesing to mention that you could consider the new JDK 7 feature of autoclosable resources.
try{
try(Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/hrdb", "obiwan", "kenobi");
Statement stm = conn.createStatement();
ResultSet rs = stm.executeQuery("select name from department")) {
while(rs.next()){
System.out.println(rs.getString("name"));
}
}
}catch(SQLException e){
//you might wanna check e.getSuppressed() as well
//log, wrap, rethrow as desired.
}
Not all of us can migrate to JDK 7 now, but for those who can start playing with the developer preview, this offer an interesting way of doing things and certainly may deprecate other approaches in the near future.
Use Lombok's cleanup, if you can:
#Cleanup
Connection c = ...
#Cleanup
statement = c.prepareStatement(...);
#Cleanup
rs = statement.execute(...);
This works translates to three nested try-finally blocks and works fine with exception. Never ever swallow an exception without a very good reason!
An alternative:
Write an own utility method like this:
public static void close(ResultSet rs, Statement stmt, Connection con) throws SQLException {
try {
try {
if (rs!=null) rs.close();
} finally {
if (stmt!=null) stmt.close();
}
} finally {
if (con!=null) con.close();
}
}
and use it in
try {
Connection con = ...
Statement stmt = ...
ResultSet rs = ...
} finally {
close(rs, stmt, con);
}
and let the Exception bubble up or handle it as you want.
Well basically that is what you do except you first of all don't necessarily swallow the exception (you can null check and at least LOG the exception). Second, you can set up a nice utility class with things like
public static void close(ResultSet rs) {
try { if (rs != null) rs.close();
} catch (SQLException (e) {
log.error("",e);
}
}
Then you just static import that class.
your finally becomes something like
finally {
close(resultset);
close(statement);
close(connection);
}
which really isn't that hideous.
You only have to close the Connection.
try
{
cStmt.close();
}
catch(Exception e)
{
/* Intentionally Swallow Exception */
}
From docs.oracle.com:
A Statement object is automatically closed when it is garbage collected. When a Statement object is closed, its current ResultSet object, if one exists, is also closed.
Calling close() on a Connection releases its database and JDBC resources.
The only way I know to hide all that ugly try-catch boilerplate code is to utilize something like Spring's JBDC Template.
You can wrap one block into another block:
try{
Connection c = ...
try{
statement = c.prepareStatement(...);
try{
rs = statement.execute(...);
}finally{
rs.close();
}
}finally{
statement.close()
}
}finally{
c.close();
}
}catch(SQLException e){}
Use the lowermost catch-block for everything that might crop up
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.