尝试使用资源:检测异常?

问题描述 投票:2回答:1

这是一个示例代码:

     try ( PgConnection conn = application.adminDb.getConnection() ) {
         // execute SQL statements here (and other possible statements)
     }

我希望AutoCloseable PgConnection类在创建时开始新事务,并在关闭时启动COMMIT或ROLLBACK。如果try块中没有抛出异常,它应该是COMMIT,否则它应该是ROLLBACK。

我真正需要的是一个上下文管理器a'la Python。有可能以某种方式这样做吗?理论上,在调用PgConnection.close()时,JVM已经知道是否存在异常。只是不知道该怎么说。

当然,我可以这样明确:

try ( PgConnection conn = application.adminDb.getConnection()) {

    conn.begin();
    try {
      // execute SQL statements here
      conn.commit();
    } catch (Exception e) {
      conn.rollback();
      throw e;
    }

}

但我需要这样做一百次,所以我正在寻找一个“减少噪音”的选项。

UPDATE

我当然可以这样做:

public interface PgTransactionWrapper {
    public void run(PgConnection connection) throws SQLException;
}

然后把它放到PgConnection中:

   public void runInTransaction(PgTransactionWrapper wrapper) throws SQLException {
       int trId = begin();
       try {
           wrapper.run(this);
           commit(trId);
       } catch (SQLException e) {
           rollback(trId);
           throw e;
       }
   }

这是如何使用它:

     try ( PgConnection conn = application.adminDb.getConnection() ) {
         conn.runInTransaction(new PgTransactionWrapper() {

            @Override
            public void run(PgConnection connection) throws SQLException {
                // SQL statements here

            }
        });
     }

但我认为情况更糟。确实实现了自动提交/回滚,但要付出的代价是更多的语法噪音,并引入了一个额外的问题:事务包装器不能抛出除SQLException之外的任何东西。

我想念的是AutoCloseable.close(Exception excOrNull)的一个简单参数,但我想这是语言的限制,而且无法完成。 :-(

更新2:只是澄清一个问题:我不想压制或转换异常。我只想在没有异常时提交,并在有异常时回滚。但除此之外,我不想从内部处理它们 - 它们应该传播给调用者,不加改变。

java try-catch
1个回答
-1
投票

以下是我对扩展代码的想法。你怎么看?至少您不必捕获异常并在整个地方处理它们以提交/回滚您的事务

public interface SQLStatementExecutor
{
    void run(PgConnection connection) throws SQLException;
}

public class PgConnectionWrapper implements Closeable
{

    private PgConnection connection;
    private boolean status = false;

    public PgConnectionWrapper()
    {
        connection = obtainConnection();
    }

    private PgConnection obtainConnection()
    {
        return application.adminDb.getConnection();
    }

    public void runInTransaction(SQLStatementExecutor executor) throws SQLException
    {
        try {
            executor.run(connection);
            status = true;
        }
        catch (SQLException e) {
            status = false;
            throw e;
        }
    }

    public PgConnection getConnection()
    {
        return connection;
    }

    @Override public void close() throws IOException
    {
        if (status) {
            connection.commit();
        }
        else {
            connection.rollback();
        }

        connection.close();
    }
}

public class TestMain
{

    public static void main(String[] args) throws IOException
    {
        try (PgConnectionWrapper connectionWrapper = new PgConnectionWrapper()) {
            connectionWrapper.runInTransaction(new SQLStatementExecutor()
            {
                @Override public void run(PgConnection connection) throws SQLException
                {
                    // SQL statements, but no commit or rollback
                }
            });
        }
    }
}

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