![](/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.