Domanda

How to integrate the common JDBC idiom of creating/receiving a connection, querying the database and possibly processing the results with Java 7's automatic resource management, the try-with-resources statement? (Tutorial)

Before Java 7, the usual pattern was something like this:

Connection con = null;
PreparedStatement prep = null;

try{
    con = getConnection();
    prep = prep.prepareStatement("Update ...");
    ...
    con.commit();
}
catch (SQLException e){
    con.rollback(); 
    throw e;
}
finally{
    if (prep != null)
        prep.close();
    if (con != null)
        con.close();
}

With Java 7 you can go for:

try(Connection con = getConnection(); PreparedStatement prep = con.prepareConnection("Update ..."){

   ...
   con.commit();
}

This will close the Connection and the PreparedStatement, but what about the rollback? I cannot add a catch clause containing the rollback, because the connection is only available within the try block.

Do you still define the connection outside of the try block? What is the best practice here, especially if connection pooling is used?

È stato utile?

Soluzione

try(Connection con = getConnection()) {
   try (PreparedStatement prep = con.prepareConnection("Update ...")) {
       //prep.doSomething();
       //...
       //etc
       con.commit();
   } catch (SQLException e) {
       //any other actions necessary on failure
       con.rollback();
       //consider a re-throw, throwing a wrapping exception, etc
   }
}

According to the oracle documentation, you can combine a try-with-resources block with a regular try block. IMO, the above example captures the correct logic, which is:

  • Attempt to close the PreparedStatement if nothing goes wrong
  • If something goes wrong in the inner block, (no matter what is is) roll back the current transaction
  • Attempt to close the connection no matter what
  • If something goes wrong closing the connection, you can't rollback the transaction (as that's a method on the connection, which is now in indeterminate state), so don't try

In java 6 and earlier, I would do this with a triply nested set of try blocks (outer try-finally, middle try-catch, inner try-finally). ARM syntax does make this terser.

Altri suggerimenti

IMO, declaring Connection and PreparedStatement outside try-catch is the best way available in this case.

If you want to use pooled connection in transaction, you should use it in this way:

try (Connection conn = source.getConnection()) {
        conn.setAutoCommit(false);
        SQLException savedException = null;
        try {
            // Do things with connection in transaction here...
            conn.commit();
        } catch (SQLException ex) {
            savedException = ex;
            conn.rollback();
        } finally {
            conn.setAutoCommit(true);
            if(savedException != null) {
                throw savedException;
            }
        }
    } catch (SQLException ex1) {
        throw new DataManagerException(ex1);
    }

This sample code handles setting autocommit values.

NOTE, that using savedException does save exception in case that conn.rollback() throws another. This way, finally block will throw "right" exception.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top