简体   繁体   English

在AutoCloseable close()中检测异常

[英]Detect exception in AutoCloseable close()

I want to build a custom AutoCloseable class so I can turn this: 我想建立一个自定义的AutoCloseable类,所以我可以打开它:

try {
    begin();
    doThings();
    commit();
} finally {
    if (transactionIsActive()) rollback();
}

into the easier 进入容易

try (Transaction t = begin()) { // too bad I have to store it in t though I don't use it
    doThings();
}

Transaction would be the AutoCloseable here and in close() it would commit or rollback the transaction as appropriate. Transaction在这里是AutoCloseable ,在close()中将适当地提交或回滚事务。

But to make that work, I would need to detect in Transaction.close() whether an exception occurred inside the try block or it completed normally. 但是要使该工作正常进行,我需要在Transaction.close()检测在try块内是否发生了异常或该异常是否正常完成。 Is this possible at all? 这有可能吗?

If it requires parsing the stack trace from a new exception, that's OK. 如果需要从新异常中解析堆栈跟踪,那就可以了。 Easier programming would be worth the tiny performance hit that brings. 更简单的编程值得带来的微小性能损失。

The closest I could come up with still requires marking the success of the transaction manually as the last statement of the block: 我能想到的最接近的仍然需要手动将事务的成功标记为该块的最后一条语句:

class Transaction implements AutoCloseable {
    private boolean rollback = true;

    public void success() {
        rollback = false;
    }

    public void close() {
        if (rollback) doRollback();
        else doCommit();
        // …
    }
}

class Main {
    public static void main(String[] args) {
        try (Transaction t = new Transaction()) {
            doThings();
            t.success();
        }
    }
}

Although my code is different from yours, I had a similar need to automatically commit (most) transactions and rollback on errors. 尽管我的代码与您的代码不同,但我有类似的需求,即自动提交(大多数)事务并回滚错误。

Most of the time my code is sprinkled with simple queries that get rolled back automatically, like this: 大多数情况下,我的代码中充斥着会自动回滚的简单查询,如下所示:

try(Transaction t : database.beginTransaction()) {
  return t.selectUnique(Employee.class, "id=?", 200);
}  // implicit rollback here

Some databases donot like queries being rolled back like this, so I've solved this by distinguishing between "write" and "read" transactions. 一些数据库不喜欢这样的查询回滚,因此我通过区分“写”和“读”事务解决了这一问题。 If it is a read transaction, close() will commit it, otherwise rollback. 如果是读事务,则close()将提交它,否则回滚。 It will also check you are not doing any write actions when you created a read-only transaction. 创建只读事务时,它还将检查您是否没有执行任何写操作。 So now I can write: 所以现在我可以写:

try(Transaction t : database.beginReadOnlyTransaction()) {
  return t.selectUnique(Employee.class, "id=?", 200);
}  // implicit commit here

Write transactions still need to call commit themselves at the end, but this is a minority of cases. 写事务最后仍需要调用commit,但这是少数情况。

I realize this is not what you asked for, but perhaps it is useful still. 我意识到这不是您要的,但也许仍然有用。

The closest I've been able to get is to explicitly call commit(), and assume that any code that exits the transaction block without doing so should be rolled back. 我能得到的最接近的方法是显式调用commit(),并假定任何不这样做而退出事务块的代码都应回滚。 This is consistent with transactions in other languages. 这与其他语言的交易保持一致。 While you can forget to call commit() (as I often do), at least this part of the code is very likely to get tested. 虽然您可以忘记调用commit()(就像我经常做的那样),但是至少这部分代码很有可能经过测试。 And, it is impossible to forget to rollback on exception, which is less likely to have test coverage. 而且,不可能忘记回滚异常,因为异常不太可能覆盖测试范围。

This is similar to millimoose's idea of setting a flag: 这类似于millimoose设置标志的想法:

try (Transaction t = new Transaction()) {
    doThings();
    t.success();
}

except that you just use the active state as the flag. 除了只使用活动状态作为标志。 Same amount of code, no new flag necessary. 相同数量的代码,不需要新的标志。 This assumes that any transaction for which commit() has not been explicitly called should be rolled back, resulting in code like this: 假定任何未显式调用commit()的事务都应回滚,从而产生如下代码:

try (Transaction t = new Transaction()) {
    doThings();
    t.commit(); // marks the transaction as successful...
}

class Transaction implements AutoCloseable {
    public void close() {
        if (isActive())
            doRollback();
    }

    ...
}

I still can't believe there is not a cleaner solution to this in the core language. 我仍然无法相信在核心语言中没有针对此的更干净的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我的AutoCloseable.close()实现可以检测到潜在的异常吗? - Can my AutoCloseable.close() implementation detect a potential exception? AutoCloseable的close方法抛出异常是否有意义? 应如何处理? - Is it meaningful for AutoCloseable's close method to throw an exception? How should this be handled? 关闭 AutoCloseable 的正确方法 - Proper way to close an AutoCloseable AutoCloseable并引发异常 - AutoCloseable and throws exception 如果实现了AutoCloseable,则帮助调用close()的助手吗? - Helper to call close() if implements AutoCloseable? 为什么java.lang.AutoCloseable的close方法会抛出异常,但java.io.Closeable的close方法会抛出IOException? - Why close method of java.lang.AutoCloseable throws Exception, but close method of java.io.Closeable throws IOException? Closeable和AutoCloseable close()方法的执行顺序 - Order of execution of Closeable and AutoCloseable close() methods 使用 AutoCloseable 关闭多个资源(try-with-resources) - Close multiple resources with AutoCloseable (try-with-resources) AutoCloseable contract:写入close()允许的资源? - AutoCloseable contract: writing to resource allowed in close()? AutoCloseable关闭方法内部的业务逻辑 - Business logic inside AutoCloseable close method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM