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

发布于 2025-01-05 15:49:12 字数 899 浏览 1 评论 0原文

如何将创建/接收连接、查询数据库以及可能处理结果的常见 JDBC 习惯与 Java 7 的自动资源管理(try-with-resources 语句)集成? (教程

在 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 块之外定义连接吗?这里的最佳实践是什么,特别是如果使用连接池?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

假装爱人 2025-01-12 15:49:12
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 文档,您可以将 try-with-resources 块与常规尝试块。 IMO,上面的示例捕获了正确的逻辑,即:

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

java 6 及更早版本中,我会使用三重嵌套的 try 块集(外部 try-finally、中间 try-catch、内部 try-finally)。 ARM 语法确实使这个更简洁。

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.

总攻大人 2025-01-12 15:49:12

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

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

谈场末日恋爱 2025-01-12 15:49:12

如果您想在事务中使用池连接,您应该以这种方式使用它:

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 块将抛出“正确”的异常。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文