On 8/8/12 7:32 AM, Kristian Waagan wrote:
On 03.08.2012 14:50, Rick Hillegas wrote:
On 8/2/12 3:29 PM, Kristian Waagan wrote:
Hello,
Has anyone considered the case of using try-with-resources (Java SE
7) with Derby connections with auto-commit off?
I haven't studied this in detail, but from what I can see the above
configuration will cause Connection.close to throw an exception if a
transaction is active. Based on what the Java API docs say, I think
Derby is behaving in a way that's allowed [1]. Nonetheless, this may
not be what users expect.
I suppose one could work around this issue with an extra try-catch
block, where you would call rollback/commit before rethrowing the
exception, but this kind of defeats the purpose of try-with-resource.
Connection.close implements AutoClosable.close so we can't have two
different behaviors for the two [2] scenarios (try-with-resources vs
explicit close).
Have I missed something that makes this problem moot?
Regards,
--
Kristian
[1] "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."
[2] Maybe one could use stack trace inspection, but that doesn't
sound like a good solution.
Hi Kristian,
Can you post a snippet of application code which you think is
mis-behaving? The following program runs correctly for me and does
not raise any exceptions.
The issue I'm talking about arises when some kind of error happens in
the program. The error itself doesn't have to be related to JDBC/SQL.
Consider this class:
----> Program
import java.sql.*;
public class TryWithResourcesDerby {
private static Connection connect()
throws SQLException {
return DriverManager.getConnection(
"jdbc:derby:memory:db;create=true");
}
public static void main(String[] args)
throws Exception {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
try (Connection con = connect()) {
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.executeUpdate("create table t (id int)");
if (true) {
throw new Exception("uhu, something went wrong");
}
stmt.executeUpdate("insert into t values 1,2,3,4,5");
}
}
}
----> Output
$ java -cp derbyrun.jar:. TryWithResourcesDerby
Exception in thread "main" java.lang.Exception: uhu, something went wrong
at TryWithResourcesDerby.main(TryWithResourcesDerby.java:19)
Suppressed: java.sql.SQLException: Cannot close a connection
while a transaction is still active.
at
org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown
Source)
at
org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
at
org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
at
org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
at
org.apache.derby.impl.jdbc.EmbedConnection.newSQLException(Unknown
Source)
at
org.apache.derby.impl.jdbc.EmbedConnection.checkForTransactionInProgress(Unknown
Source)
at
org.apache.derby.impl.jdbc.EmbedConnection.close(Unknown Source)
at
TryWithResourcesDerby.main(TryWithResourcesDerby.java:22)
Caused by: java.sql.SQLException: Cannot close a connection
while a transaction is still active.
at
org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown
Source)
at
org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown
Source)
... 8 more
I understand why this happens, but in this case my intention was to
wrap the connection creation in try-with-resources simply so I could
just forget about it :)
As Rick already mentioned, changing the behavior would have backward
compatibility issues.
We could add some documentation, but I assume most people would figure
this out and deal with it in their code (i.e. a second try-catch
block, or in some cases maybe a catch-clause in the try-with-resources
block would be sufficient). What we don't want to see is people
turning auto-commit on just to avoid this behavior :)
Thanks for the code snippet, Kristian. I don't see this as a Derby
problem. It might make sense for the JDBC spec to point out the
undefined AutoClosable behavior of Connection:
o Statements and ResultSets have well defined close() semantics and can
be used portably in try-with-resources blocks.
o But the behavior of Connection.close() is undefined. This makes it
hard to write portable code which declares Connections in
try-with-resources blocks.
Thanks,
-Rick