![](/img/trans.png)
[英]Can my AutoCloseable.close() implementation detect a potential exception?
[英]Detect exception in AutoCloseable close()
我想建立一个自定义的AutoCloseable
类,所以我可以打开它:
try {
begin();
doThings();
commit();
} finally {
if (transactionIsActive()) rollback();
}
进入容易
try (Transaction t = begin()) { // too bad I have to store it in t though I don't use it
doThings();
}
Transaction
在这里是AutoCloseable
,在close()
中将适当地提交或回滚事务。
但是要使该工作正常进行,我需要在Transaction.close()
检测在try块内是否发生了异常或该异常是否正常完成。 这有可能吗?
如果需要从新异常中解析堆栈跟踪,那就可以了。 更简单的编程值得带来的微小性能损失。
我能想到的最接近的仍然需要手动将事务的成功标记为该块的最后一条语句:
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();
}
}
}
尽管我的代码与您的代码不同,但我有类似的需求,即自动提交(大多数)事务并回滚错误。
大多数情况下,我的代码中充斥着会自动回滚的简单查询,如下所示:
try(Transaction t : database.beginTransaction()) {
return t.selectUnique(Employee.class, "id=?", 200);
} // implicit rollback here
一些数据库不喜欢这样的查询回滚,因此我通过区分“写”和“读”事务解决了这一问题。 如果是读事务,则close()将提交它,否则回滚。 创建只读事务时,它还将检查您是否没有执行任何写操作。 所以现在我可以写:
try(Transaction t : database.beginReadOnlyTransaction()) {
return t.selectUnique(Employee.class, "id=?", 200);
} // implicit commit here
写事务最后仍需要调用commit,但这是少数情况。
我意识到这不是您要的,但也许仍然有用。
我能得到的最接近的方法是显式调用commit(),并假定任何不这样做而退出事务块的代码都应回滚。 这与其他语言的交易保持一致。 虽然您可以忘记调用commit()(就像我经常做的那样),但是至少这部分代码很有可能经过测试。 而且,不可能忘记回滚异常,因为异常不太可能覆盖测试范围。
这类似于millimoose设置标志的想法:
try (Transaction t = new Transaction()) {
doThings();
t.success();
}
除了只使用活动状态作为标志。 相同数量的代码,不需要新的标志。 假定任何未显式调用commit()的事务都应回滚,从而产生如下代码:
try (Transaction t = new Transaction()) {
doThings();
t.commit(); // marks the transaction as successful...
}
class Transaction implements AutoCloseable {
public void close() {
if (isActive())
doRollback();
}
...
}
我仍然无法相信在核心语言中没有针对此的更干净的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.