我已经为此苦苦挣扎了一段时间。我不喜欢 Jon Skeet 的回答,因为开发人员(即我)可能会不小心忘记调用commitOnClose()
. 我想要一种让开发人员在离开代码块时被迫调用 commit() 或 rollback() 的方法。
Lambda 和检查的异常不能很好地结合在一起,所以一个合适的解决方案有点令人费解,但最终我和我的一个同事想出了一段代码,让你可以像这样工作:
TransactionEnforcer.DbResult<String> result = transactionEnforcer.execute(db -> {
try {
db.someFunctionThatThrowsACheckedException();
} catch (TheException e) {
return failure("fallback value");
}
return success(db.getAFancyValue());
});
result.ifPresent(v -> System.out.println(v));
请注意如何返回值,检查代码是否成功,并且 java 的代码路径返回检查强制您始终明确说明是否应提交代码。
它是使用下面的代码实现的:
package nl.knaw.huygens.timbuctoo.database;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
public class TransactionEnforcer {
private final Supplier<DbClass> dbClassFactory;
public TransactionEnforcer(Supplier<DbClass> dbClassFactory) {
this.dbClassFactory = dbClassFactory;
}
public <U> DbResult<U> execute(Function<DbClass, DbResult<U>> actions) {
DbClass db = dbClassFactory.get();
try {
DbResult<U> result = actions.apply(db);
if (result.isSuccess()) {
db.close(true);
} else {
db.close(false);
}
return result;
} catch (RuntimeException e) {
db.close(false);
throw e;
}
}
public static class DbResult<T> {
private final Optional<T> value;
private final boolean success;
private DbResult(T value, boolean success) {
this.value = Optional.of(value);
this.success = success;
}
public static <T> DbResult<T> success(T value) {
return new DbResult<T>(value, true);
}
public static <T> DbResult<T> success() {
return new DbResult<T>(null, true);
}
public static <T> DbResult<T> failure(T value) {
return new DbResult<T>(value, false);
}
public static <T> DbResult<T> failure() {
return new DbResult<T>(null, false);
}
public boolean isSuccess() {
return success;
}
public Optional<T> getValue() {
return value;
}
}
}
(我将 DbClass 作为练习留给读者)