java - 使用新的 try-with-resources block 在 SQLException 上回滚事务

标签 java try-with-resources

我对 try-with-resources 有疑问,我只是想确定一下。如果我需要对异常使用react,并且我仍然需要 catch block 中的资源,我可以使用它吗?给出的例子是这样的:

try (java.sql.Connection con = createConnection())
{
    con.setAutoCommit(false);
    Statement stm = con.createStatement();
    stm.execute(someQuery); // causes SQLException
}
catch(SQLException ex)
{
    con.rollback();
    // do other stuff
}

我担心在这种情况下我仍然注定要使用旧的 try-catch-finally,即使根据 oracle 文档 - “catch and finally blocks in a try-with-resources statement, any catch or finally block is run在声明的资源关闭之后。”

最佳答案

根据语言规范,连接将在 catch 子句执行之前关闭 (http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3.2)。

一种可能的解决方案是嵌套 try-with-resources 语句:

try (java.sql.Connection con = createConnection())
{
    con.setAutoCommit(false);
    try (Statement stm = con.createStatement())
    {
        stm.execute(someQuery); // causes SQLException
    }
    catch(SQLException ex)
    {
        con.rollback();
        con.setAutoCommit(true);
        throw ex;
    }
    con.commit();
    con.setAutoCommit(true);
}

希望这能说明这一点。如果您打算在生产代码中使用它,这应该会有所改进。

例如,如果您正在使用连接池,那么您必须在获得连接时返回连接,因此 con.setAutoCommit(true);应该在 finally 子句中完成。这意味着外部的 try-with-resources 应该是传统的 try-catch-finally。

编辑(2018 年)

我仍然看到人们对此发表评论,所以我想我会在 2018 年回复它。我不再使用Java了,主要是使用Scala、Clojure和Kotlin,并且这段代码没有经过测试,所以请把这当作另一个例子。但是,由于 Java 有 lambda,我认为以下方法要好得多。我在其他语言的生产代码中也做过类似的事情。

在这种方法中,有一个 inTransaction 函数来处理所有令人讨厌的事务。但是用法很简单。

public class Foo {

    interface ConnectionProvider {
        Connection get() throws SQLException;
    }

    public static <A> A doInTransation(ConnectionProvider connectionProvider, Function<Connection, A> f) throws SQLException {
        Connection connection = null;
        A returnValue;
        boolean initialAutocommit = false;
        try {
            connection = connectionProvider.get();
            initialAutocommit = connection.getAutoCommit();
            connection.setAutoCommit(false);
            returnValue = f.apply(connection);
            connection.commit();
            return returnValue;
        } catch (Throwable throwable) {
            // You may not want to handle all throwables, but you should with most, e.g.
            // Scala has examples: https://github.com/scala/scala/blob/v2.9.3/src/library/scala/util/control/NonFatal.scala#L1
            if (connection != null) {
                connection.rollback();
            }
            throw throwable;
        } finally {
            if (connection != null) {
                try {
                    if(initialAutocommit){
                        connection.setAutoCommit(true);
                    }
                    connection.close();
                } catch (Throwable e) {
                    // Use your own logger here. And again, maybe not catch throwable,
                    // but then again, you should never throw from a finally ;)
                    StringWriter out = new StringWriter();
                    e.printStackTrace(new PrintWriter(out));
                    System.err.println("Could not close connection " + out.toString());
                }
            }
        }
    }

    public static void main(String[] args) throws SQLException {
        DataSource ds = null;

        // Usage example:
        doInTransation(ds::getConnection, (Connection c) -> {
            // Do whatever you want in a transaction
            return 1;
        });
    }
}

我希望有一些经过实战考验的库可以为你做这些事情,至少在这些其他语言中是这样的。

我看到有一些关于自动提交和连接池的评论。上面的例子应该不知道连接来自哪里,一个池与否,即只有当它是初始值时才将它设置回 true。因此,如果从池中它是错误的,则不应触摸它。

关于 try-with-resources 的最后一句话。我不认为这是一个很好的抽象,所以我会在更复杂的场景中小心使用它。

关于java - 使用新的 try-with-resources block 在 SQLException 上回滚事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15761791/

相关文章:

java - 尝试为银行应用程序调用名为 addAccount 的方法,但它一直给出 .class is Expected 错误

java - 为什么我会收到空​​指针异常?

java - "Self-suppression not permitted"究竟是什么?为什么 Javac 生成的代码会导致此错误?

java - 尝试资源的 8 个分支 - 可以进行 jacoco 覆盖吗?

java - 代码在子类中是如何工作的?

Java:如何 "trim"字节数组?

java - 使用 gwt-crypto 库通过 Google App Engine 在 Google Web Toolkit 应用程序上生成客户端 RSA key 对

Java Try-With-Resources 未知资源计数

java - 谁捕获异常,在 close 方法中出现?(try-with-resources)

java - FileInputStream 和关闭