I have a problem with try-with-resources and I am asking just to be sure. Can I use it, if I need to react on exception, and I still need the resource in catch block? Example given is this:
try (java.sql.Connection con = createConnection())
{
con.setAutoCommit(false);
Statement stm = con.createStatement();
stm.execute(someQuery); // causes SQLException
}
catch(SQLException ex)
{
con.rollback();
// do other stuff
}
I fear that I am still doomed to use the old try-catch-finally in this case, even according to oracle documentation - "catch and finally blocks in a try-with-resources statement, any catch or finally block is run after the resources declared have been closed."
In the example above I think it's better to put
con.commit()
inside nestedtry-catch
because it also can throwSQLException
.We had such problem in our production environment with unclosed sessions.
In your code you are catching "SQLException" to perform the autoCommit reset. Any kind of runtime exception (like a null pointer exception) will bubble from your code without resetting the auto-commit.
The try-with-resource syntax causes the compiler to generate some wonderful code to cover all execution paths and to keep up with all suppressed exceptions through the closings. With a couple of helper classes you can insert commit/rollback and reset-auto-commit into the code generation process:
Now you can control rollback and autocommit with the "try with resource" syntax like this:
According to the language spec, the connection will be closed before the catch clause is executed (http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3.2).
A possible solution is to nest try-with-resources statements:
Hopefully that illustrates the point. This should be improved quite a bit if you plan on using it in production code.
For instance, if you are using a connection pool, then you must return the connection as you got it, so con.setAutoCommit(true); should be done in a finally clause. This would mean that the outer try-with-resources should be a traditional try-catch-finally.
Edit (2018)
I see people commenting on this still, so I thought I'd give it a 2018 reply. I am not working in Java anymore, mainly been working in Scala, Clojure and Kotlin, and this code has not been tested, so please treat this as just another example. However since Java has lambdas, I think the following approach is a lot better. And I've done similar things in production code in these other languages.
In this approach there is a inTransaction function handling all the nasty transaction stuff. But usage is pretty simple.
I would hope there is some battle tested libraries out there doing this stuff for you, there is at least in these other languages.
I see there are several comments regarding autocommit and connection pools. The above examples should be agnostic to where the connection came from, a pool or not, i.e. only setting it back to true if that was it's initial value. So if from a pool it is false, it should not be touched.
A final word on try-with-resources. I don't think it is a very good abstraction, so I'd be careful using it in more complex scenarios.