db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rick Hillegas <rick.hille...@oracle.com>
Subject Re: Java 7 try-with-resources (AutoClosable) on Derby connections with auto-commit off
Date Wed, 08 Aug 2012 15:12:42 GMT
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


Mime
View raw message