我想构建一个自定义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块内是否发生了异常,或者它是否正常完成。这有可能吗?
如果它需要从新的异常中解析堆栈跟踪,那就没问题。更容易编程将值得带来微小的性能损失。
答案 0 :(得分:6)
我能提出的最接近的仍然需要手动将交易成功标记为该块的最后一个陈述:
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();
}
}
}
答案 1 :(得分:1)
虽然我的代码与您的代码不同,但我有类似的需要自动提交(大多数)事务并回滚错误。
大多数情况下,我的代码中都会出现自动回滚的简单查询,如下所示:
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,但这只是少数情况。
我意识到这不是你要求的,但也许它仍然有用。
答案 2 :(得分:0)
我能够得到的最接近的是显式调用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();
}
...
}
我仍然无法相信核心语言中没有更清晰的解决方案。