Is rollback needed if java.sql.Connection#commit() throws exception? - java

According to JAVA documentation, Connection#commit() can throw SQLException. My question is whether or not a rollback should still be issued in this scenario.
For example:
Connection con = null;
try {
// assume this method returns an opened connection with setAutoCommit(false)
con = createConnection();
// do DB stuff
con.commit();
} catch (SQLException e) {
if (con != null) {
// what if con.commit() failed, is this still necessary,
// will it hurt anything?
con.rollback();
}
} finally {
if (con != null) {
con.close();
}
}
I actually wrapped the con.rollback() call into another method which ignores any exceptions thrown by it, so I think I'm ok here. I just wondered if this was the best way of handling things.

Rollback is important even if commit failed, according to the Java 1.6 JDBC docs:
It is strongly recommended that an application explicitly commits or
rolls back an active transaction prior to calling the close method. If
the close method is called and there is an active transaction, the
results are implementation-defined.
This means that if you do not explicitly invoke rollback, some JDBC implementation might invoke commit before closing the connection.
Another good reason to rollback is as Xepoch suggested and when using a connection pool it is even more important.
When getting a connection from a connection pool, most implementations will execute connection.setAutoCommit(defaultAutoCommit) before giving you the connection and according to the JavaDocs:
If this method is called during a transaction and the auto-commit mode
is changed, the transaction is committed
If the connection.rollback() throws an exception - then it is a tricky one...

I would do explicit rollback just for clean-up purposes. Although changes won't be persisted in db either way, it seems nice to explicitly let database know that you're done here. Just like the way you close connection explicitly, without waiting for Connection object to be garbage-collected.
This is, obviously, not a technical answer and I would also be interested to learn whether there's a practical point in doing so.

"Returns an open connection?" If that connection is shared in a pool (and could be in the future) you don't want another transaction committing your earlier work. I've seen MANY customer/solution cases of plugging in pooled connection driver that comply with JDBC interfaces and Connection.close() can also be used to just return the Connection back to a pool.
Also, better try{}catch{} your rollback() (edit, just read your whole post, but I always like to log an exception on rollback)

The usual way I do this is:
boolean bSuccess = false;
Connection con = null;
try {
// assume this method returns an opened connection with setAutoCommit(false)
con = createConnection();
// do DB stuff
bSuccess = true;
} catch (SQLException e)
{
}
finally
{
try
{
if (con != null)
{
if(bSuccess)
con.commit()
else
con.rollback();
con.close();
}
}
catch(SQLException sqle)
{
log("Log the error here");
// do nothing we tried
}
}
That being said I have never seen a commit or a rollback fail if the queries worked.
If you have pending transactions then most databases have tools to free them. Most app servers will keep retrying the commits and rollbacks until they can connect.
You might want to look at this post: Is it necessary to write ROLLBACK if queries fail?

Related

Will con.rollback() rollback already commited changes by con.commit()?

I am working on Legacy project now and it requires some deep knowledge of low level JDBC API
in some places I see code like this:
try {
con = ....
con.setAutoCommit(false);
//insert_1 pack to db
con.commit();
//insert_2 pack to db
con.commit();
//insert_3 pack to db
con.commit();
} catch (SQLException e) {
try {
con.rollback();
} catch (SQLException e) {
log.warn("SQLException on rolling back the destination connection. ", e);
throw e;
}
throw ex;
}
and sometimes con.rollback(); is not invoked in the the catch:
try {
con = ....
con.setAutoCommit(false);
//insert_1 pack to db
con.commit();
//insert_2 pack to db
con.commit();
//insert_3 pack to db
con.commit();
} catch (SQLException e) {
throw new MyBusinessException(ex);
}
Could you please explain difference from transaction standpoint ?
P.S.
I've read java doc for rollback but it doesn't answer my question.
Undoes all changes made in the current transaction and releases any
database locks currently held by this Connection object. This method
should be used only when auto-commit mode has been disabled. Throws:
SQLException – if a database access error occurs, this method is
called while participating in a distributed transaction, this method
is called on a closed connection or this Connection object is in
auto-commit mode See Also: setAutoCommit
The code looks incorrect.
There are several commits executed. This would mean that the explicit rollback could just rollback the state to the beginning of the last commit. This is, I guess, not what the rollback should do.
If no explicit rollback is called, at least in a pooled database connection (in a pooled database connection the connection is never closed, but reused) the already executed statements are still in transaction. I.e. calling here a rollback later would lead to strange kind of errors and also rolling back the last executed statements actually not related to the current business process. I see in the Hikari Connection Pool Implementation that dirty states are automatically rolled back, but maybe this correct behavior cannot be assumed for every implementation. E.g. the Apache DBCP is not that straight forward in the code and asking the maintainers if they are doing this should be helpful.
I see no close call.
For your questions this means the second code snippet should:
In a single non pooled connection not commit the last statements after the last commit, this is what would be correct (by accident).
In a pooled connection leave the transactions pending which could lead to the error that the next business logic committing something and reusing the connection will also commit this.

Why JDBC connections needs to close in finally block?

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try
{
conn = geting the connection object ( using DriverManager.getConnection() method or using connection pool)
stmt = conn.createStatement ("select ...");
// some other logic here
}
catch (SQLException e)
{
// handling the exceptions
}
finally
{
}
Here my question is while closing the connection object in the following cases what are the problems it will come.
Assume if there is no exception occurred, in try block there it self closing the connection object.
try {
// same above code
stmt.close();
conn.close();
} catch(Exception ex) {
// handling the exceptions
} finally {
}
If some exception is occured so it will goes to catch block, there it self closing the connection object.
try {
// same above code
} catch(Exception ex) {
// handling the exceptions
stmt.close();
conn.close();
} finally {
}
Closing the connection object in finally block.
try {
// same above code
} catch(Exception ex) {
// handling the exceptions
} finally {
stmt.close();
conn.close();
}
Difference between closing the connection object using close() method and closing the pooled connection using close().
Note: Please don't say closing the connection object in finally block is good. I know that one. If i keep the close connection in try block, catch block is there any problems please explain.
It is recommended to close the connection in the finally block because if you have multiple catch blocks (as you should: you should never catch generic Exception) you will not have to re-write the closing statements.
A finally block will always be executed after a try, no matter what happens. So if you get a NullPointerException, or some other exception you didn't handle, with the finally block you will be sure that your resources are closed properly.
But if you are on java 7, I'd suggest to use the try-with-resources block
As database is consuming more resources, it is always recommended to close your connection after your processing is done whether successfully or not.
You said that adding conn.close() in try, this is fine if your query runs without any exception and what if your query has any issues, the connection would not be closed. So it is always recommended to close your connection in finally block which is executed always irrespective of whether exception occurred or not. Also if you try to put the closing statement in catch block and your trying to handle multiple exceptions you will need to repeat your code which is not recommended.
Answer is that 'We must close the connection after using it.' But the actual question is why we must close the connection after using?.
1.) When we create a connection with a remote database server lets say MySQL Server, It also keeps a connection open for you. Due there is a also a limitation/configuration at database server end for number of connection allowed. If we don't close the connection from our end it will remain open and such way after a short while number of allowed connections will be exceeded at database server end and we will not be able to make further connection with that database.
2.) Auto release connections time setting at database server side.
If we don't close connection from our end and we don't execute any query for certain period of time (As I think default time setting in MySql is 28800 sec. means 8 Hrs. Although we can change it.) it will automatically release the connection from server end.
Important! What will happen in that situation when your jdbc Connection object is really released at database server end and you think it is still connected because you never disconnected/closed it and you are trying to executing query on that connection using statement. Really critical.
That's why we must always close the connection and execute statement on connected connection object.
The finally block is always executed, including the following cases:
Normal termination of the try-block.
Exceptional termination of the try-block when exception is handled in some catch.
Exceptional termination when exception is propagated to the caller.
A return statement in the middle of the block:
try {
if(something) return false; // finally is executed here as well
...
} finally { ... }
A break or continue statement if the whole try-catch is inside the loop:
while(condition) {
try {
if(something) continue; // finally is executed here
else if(somethingElse) break; // finally is executed here
...
}
finally {
}
}
Thus no matter how you exit the try block, the finally will be executed and you should not care about checking every possible exiting way. This is really convenient.
finally block always execute :
try{
// code logic
}catch(SQLException ex){
// catch exception
}finally{
if (dbConnection != null){
dbConnection.close();
}
}
What happens if an exception you're not handling gets thrown? (I
hope you're not catching Throwable...)
What happens if you return from inside the try block?
What happens if the catch block throws an exception?
A finally block makes sure that however you exit that block (modulo a few ways of aborting the whole process explicitly), it will get executed. That's important for deterministic cleanup of resources.
Note : Also for preventing application resource leaking we have to close connection anyway..!!
Thanks.!!
You can close connection in try or in catch block, but will tell you why is good to close connection in finally Block
Suppose you have try catch block as below:
try{
stmt1..
stmt2..
conn.close
}
catch(exception e){
}
Now suppose exception is raised by stm1 then your connection will remain open.
Now consider you are closing connection in catch block..what if no exception raised then control will never come in catch block.. here connection is still open.. I hope i am able to clear few of you doubts.

Working with Java & SQL

I have been playing around with JDBC drivers. I would like some advice from the experience code masters out there. I was wondering if this is a good way to find if am connected to a database. If it is not, could someone let me know how would they do it?
Connection con = null;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost/"+database+"?+user="+user+"&password="+password);
} catch (SQLException e) {
System.out.println(e.getMessage());
if (con != null) {
System.out.println("hello");
} else {
System.out.println("Not Connected!");
}
}
I would really appreciate all helpful comments. Many thanks in advance.
If the getConnection method returns normally, and does not throw an exception, then a connection to the database has been made. The logic within the catch clause is unrequired, because if an exception is caught a connection was not established.
The returned Connection object must be close()d (as many of the JDBC classes must, such as Statements and ResultSets for example). Assuming Java7, a convenient way to ensure the Connection is closed is using the try-with-resources statement:
try (Connection con = DriverManager.getConnection(...))
{
}
catch (final SQLException e)
{
}
As stated by SnakeDoc in the comments this may be impractical in production systems because establishing a connection to the database is a typically expensive operation.
The JDBC API will perform these checks for you. Whenever you perform a database operation, such as opening a connection, executing a statement, it will check to see if the connection is valid. If not it will throw an exception.
For example, the method Connection.createStatement throws the following:
SQLException - if a database access error occurs or this method is called on a closed connection
All you have to do is some basic exception handling. Surrounding your JDBC calls with try-catch blocks is one way do this. You could also throw the exception and handle it somewhere else.
That's definitely a good way of doing it! If conn can't be initialised it's either your connection string that is wrong or the database is down.

Closing JDBC Connections in Pool

Our standard code section for using JDBC is...
Connection conn = getConnection(...);
Statement stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet rset = stmt.executeQuery (sqlQuery);
// do stuff with rset
rset.close(); stmt.close(); conn.close();
Question 1: When using Connection Pool, should one close the Connection at the end? If so, isn't the purpose of pooling lost? And if not, how does the DataSource know when a particular instance of Connection is freed up and can be reused? I am a little confused on this one, any pointers appreciated.
Question 2: Is the following method anything close to standard? Looks like an attempt to get a connection from the pool, and if DataSource cannot be established, use the old fashioned DriverManager. We are not even sure which part is getting executed at runtime.
Repeating the question above, should one close the Connection coming out of such a method?
synchronized public Connection getConnection (boolean pooledConnection)
throws SQLException {
if (pooledConnection) {
if (ds == null) {
try {
Context envCtx = (Context)
new InitialContext().lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
return ds.getConnection();
} catch (NamingException e) {
e.printStackTrace();
}}
return (ds == null) ? getConnection (false) : ds.getConnection();
}
return DriverManager.getConnection(
"jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}
Edit: I think we are getting the pooled connection since we do not see a stack trace.
When using Connection Pool, should one close the Connection at the end? If so, isn't the purpose of pooling lost? And if not, how does the DataSource know when a particular instance of Connection is freed up and can be reused? I am a little confused on this one, any pointers appreciated.
Yes, certainly you need to close the pooled connection as well. It's actually a wrapper around the actual connection. It wil under the covers release the actual connection back to the pool. It's further up to the pool to decide whether the actual connection will actually be closed or be reused for a new getConnection() call. So, regardless of whether you're using a connection pool or not, you should always close all the JDBC resources in reversed order in the finally block of the try block where you've acquired them. In Java 7 this can be further simplified by using try-with-resources statement.
Is the following method anything close to standard? Looks like an attempt to get a connection from the pool, and if DataSource cannot be established, use the old fashioned DriverManager. We are not even sure which part is getting executed at runtime. Repeating the question above, should one close the Connection coming out of such a method?
The example is pretty scary. You just need to lookup/initialize the DataSource only once during application's startup in some constructor / initialization of an applicationwide DB config class. Then just call getConnection() on the one and same datasource throughout the rest of application's lifetime. No need for synchronization nor nullchecks.
See also:
Is it safe to use a static java.sql.Connection instance in a multithreaded system?
Am I Using JDBC Connection Pooling?
The pools typically return you a wrapped Connection object, where the close() method is overridden, typically returning the Connection to the pool. Calling close() is OK and probably still required.
A close() method would probably look like this:
public void close() throws SQLException {
pool.returnConnection(this);
}
For your second question, you could add a logger to show whether the bottom block ever runs. I would imagine though you'd only want one way or the other for the configuration of your database connections. We solely use a pool for our database accesses. Either way, closing the connection would be pretty important to prevent leaks.
Actually, the best approach to connection management is to not farm them out to any code anywhere.
Create a SQLExecutor class that is the one and only location which opens and closes connections.
The entire rest of the application then pumps statements into the executor rather than getting connections from the pool and managing (or mismanaging them) all over the place.
You can have as many instances of the executor as you want, but no one should be writing code that opens and closes connections on its own behalf.
Conveniently, this also lets you log all your SQL from a single set of code.

In JDBC, when autocommit is false and no explicit savepoints have been set, is it good style or a waste to rollback?

Say you have the following code:
Connection conn;
try
{
conn = ... // get connection
conn.setAutoCommit(false);
... // Do some modification queries and logic
conn.commit()
} catch(SQLException e)
{
conn.rollback() // Do we need this?
conn.close()
}
In this code, if there is an exception, is it better style to just close the connection (since autocommit is off), or to explicitly roll back and then close the connection? There are no save points.
I feel that it might make sense to add the rollback call because:
1) Someone, in the future, might add save points but forget to add the rollback
2) It improves readability
3) It shouldn't cost anything, right ?
But obviously, none of these is particularly compelling. Any standard practice?
Note: I'm aware of the need to do a repeat try/catch on closing and rollback. I actually have a middleware that abstracts the database access and takes care of that, but I was wondering whether adding it was superfluous.
The normal idiom is the following:
public void executeSomeQuery() throws SQLException {
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
try (PreparedStatement statement = connection.prepareStatement(SOME_SQL)) {
// Fire transactional queries here.
connection.commit();
} catch (SQLException e) {
connection.rollback();
throw e;
}
}
}
Note that Java 7's try-with-resources statement always implicitly calls close() on the resource when the try block finishes, as if it happens in finally.
Calling rollback() is also mandatory when it concerns a pooled connection. Namely, it will reset the transactional state of the connection. The close() of a pooled connection won't do that, only the commit() and rollback() will do that. Not calling rollback() may lead that the next lease of the pooled connection will still have the (successful) queries of the previous transaction in its memory.
See also javadoc of Connection#close() (emphasis not mine):
It is strongly recommended that an application explicitly commits or rolls back an active transaction prior to calling the close method. If the close method is called and there is an active transaction, the results are implementation-defined.
Closing should rollback because it will not commit when the resources are release, but it's good to have your error handling be specific, so if you want to rollback on an exception, do that. Then you can do your cleanup in a finally{} block. The rollback() occurs only on error, in which case your commit() is not successful or was not even reached.
Connection conn = null;
try {
conn = ...
...
conn.commit();
}
catch (SQLException e) {
if (conn != null) {
conn.rollback();
}
}
finally {
if (conn != null) {
conn.close();
}
}

Categories