Java 7自动资源管理JDBC(try-with-resources语句)

问题描述 投票:37回答:3

如何集成Java创建/接收连接,查询数据库以及可能使用Java 7的自动资源管理(try-with-resources语句)处理结果的通用JDBC习惯? (Tutorial

在Java 7之前,通常的模式是这样的:

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();
}

使用Java 7,您可以申请:

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

   ...
   con.commit();
}

这将关闭ConnectionPreparedStatement,但是回滚又如何呢?我无法添加包含回滚的catch子句,因为该连接仅在try块内可用。

您还在try块之外定义连接吗?最佳实践是什么,尤其是使用连接池时?

java jdbc java-7 try-with-resources
3个回答
39
投票
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
   }
}

根据oracle documentation,您可以将try-with-resources块与常规try块组合。 IMO,以上示例捕获了正确的逻辑,即:

  • 如果没有问题,请尝试关闭PreparedStatement
  • 如果内部块出了问题,(无论是什么)回滚当前事务
  • 无论如何尝试关闭连接
  • 如果在关闭连接时出现问题,则无法回滚事务(因为这是连接上的方法,现在处于不确定状态,所以请不要尝试

在Java 6和更早版本中,我将使用三重嵌套的try块集(外部try-finally,中间try-catch,内部try-finally)进行此操作。 ARM语法确实使这个麻烦。


4
投票

IMO,在try-catch之外声明Connection和PreparedStatement是这种情况下的最佳方法。


2
投票

如果要在事务中使用池化连接,则应以这种方式使用它:

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);
    }

此示例代码处理设置自动提交值。

注意,使用savedException确实可以保存异常,以防conn.rollback()抛出另一个异常。这样,finally块将抛出“正确的”异常。

© www.soinside.com 2019 - 2024. All rights reserved.