当前位置: 首页 > 面试题库 >

使用新的try-with-resources块对SQLException进行事务回滚

汤跃
2023-03-14
问题内容

我在尝试资源时遇到问题,我只是想确定一下。如果我需要对异常做出反应并且仍然需要catch块中的资源,可以使用它吗?给出的示例是这样的:

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
}

我担心即使在oracle文档中,我仍然注定要在这种情况下最终使用旧的try-catch-finally-“在try-with-
resources语句中捕获并最终阻止,任何catch或finally块都在资源之后运行宣布已关闭。”


问题答案:

根据语言规范,将在执行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-catch。

编辑(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。因此,如果在池中为假,则不应触摸它。

关于尝试资源的最终决定。我认为这不是一个很好的抽象,因此在更复杂的场景中使用它时要格外小心。



 类似资料:
  • 我在尝试资源方面有问题,我只是想确认一下。如果我需要对异常做出反应,并且我仍然需要catch块中的资源,我可以使用它吗?示例如下: 我担心在这种情况下,我仍然注定要使用旧的try-catch-最终,即使根据甲骨文留档-“在try-with-资源语句中,任何一抓或最终块都是在声明的资源被关闭后运行的。”

  • 主要内容:Java SE 7:Try-With-Resources基础知识,Java SE 7:Try-With-Resources规则,Java SE 9:Try-With-Resources改进在这篇文章中,我们将讨论Java SE 9中的一些改进语句。现在让我们开始学习这个构造。 Java SE 7:Try-With-Resources基础知识 Java SE 7引入了一个新的构造: 语句,用于更好的异常处理。 如果没有这个构造,开发人员必须编写大量冗余和难看的代码。 如果开发人员忘记正确

  • try-with-resources语句是一个try语句,其中包含一个或多个正式声明的资源。 这里资源是一个对象,一旦不再需要就应该关闭它。 try-with-resources语句确保在需求完成后关闭每个资源。 任何实现java.lang.AutoCloseable或java.io.Closeable的对象,接口都可以用作资源。 在Java 9之前,资源将在try之前或try语句内部声明,如下面

  • 下面的try with resources语句是来自Java文档的示例 根据文件, 用资源尝试语句确保每个资源在语句末尾关闭。 我的问题是,为什么我需要在try关键字之后立即在括号内声明资源。(如上面的BuffereReader) BufferReader实现了java。lang.AutoCloseable 所以为什么不支持这样的事情, 一旦退出尝试,就隐式关闭资源对象。(正如它所实现的自动关闭)

  • 本文向大家介绍如何在JDBC中使用try-with-resources?,包括了如何在JDBC中使用try-with-resources?的使用技巧和注意事项,需要的朋友参考一下 每当我们实例化并使用某些对象/资源时,都应显式关闭它们,否则有可能发生资源泄漏。 通常,我们使用finally资源使用close资源作为- 从JSE7开始,引入了try-with-resources语句。在这种情况下,我

  • 问题内容: 我读到try-with-resources 中的块是可选的。我试图在try-with- resources块中创建一个对象,没有后续块,只是从eclipse中获取编译器错误:“ 自动调用引发了未处理的异常类型。” 由于可以在try-with- resources中使用的每个资源都实现了,因此在调用该方法时可能会引发异常,因此我不明白该子句是可选的,因为它不允许我跳过从中捕获异常的过程。