【发布时间】:2017-12-17 06:21:21
【问题描述】:
这是一个示例代码:
try ( PgConnection conn = application.adminDb.getConnection() ) {
// execute SQL statements here (and other possible statements)
}
我希望 AutoCloseable PgConnection 类在创建时开始新事务,并在关闭时提交或回滚。如果在 try 块中没有抛出异常,它应该 COMMIT,否则它应该 ROLLBACK。
我真正需要的是一个上下文管理器 a'la Python。有可能以某种方式做到这一点吗?理论上,在调用 PgConnection.close() 时,JVM 已经知道是否存在异常。就是不知道怎么说。
当然我可以这样说:
try ( PgConnection conn = application.adminDb.getConnection()) {
conn.begin();
try {
// execute SQL statements here
conn.commit();
} catch (Exception e) {
conn.rollback();
throw e;
}
}
但我需要这样做一百次,所以我正在寻找一个“噪音较小”的选项。
更新
我当然可以这样做:
public interface PgTransactionWrapper {
public void run(PgConnection connection) throws SQLException;
}
然后把这个放到PgConnection中:
public void runInTransaction(PgTransactionWrapper wrapper) throws SQLException {
int trId = begin();
try {
wrapper.run(this);
commit(trId);
} catch (SQLException e) {
rollback(trId);
throw e;
}
}
这就是它的使用方法:
try ( PgConnection conn = application.adminDb.getConnection() ) {
conn.runInTransaction(new PgTransactionWrapper() {
@Override
public void run(PgConnection connection) throws SQLException {
// SQL statements here
}
});
}
但我认为情况更糟。确实实现了自动提交/回滚,但付出的代价是更多的语法噪音,并且引入了一个额外的问题:事务包装器除了 SQLException 不能抛出任何东西。
我想念的是 AutoCloseable.close(Exception excOrNull) 的一个简单参数,但我想这是语言的限制,无法做到。 :-(
更新 2:只是为了澄清问题:我不想抑制或转换异常。我只想在没有异常的时候提交,在有异常的时候回滚。但除此之外,我不想从内部处理它们——它们应该原封不动地传播给调用者。
【问题讨论】:
-
一个围绕 PgConnection 的可自动关闭的包装类,它在关闭时根据 on 状态自动提交/回滚(默认:不成功,除非另有明确设置)?
-
可以,但是如何设置状态呢?如果我想在 catch 子句中设置状态,那么我必须为每个单独的用例创建一个额外的 try/catch 块。我认为这会比我的“显式”示例更糟糕,因为它仍然会增加语法噪音,并用隐式的替换显式提交/回滚。
-
您的最后一个示例很嘈杂,因为您没有使用 lambda 表达式,并且存在异常问题,因为您仍在使用检查异常而不是运行时异常(尽管如果try 块在 runInTransaction()) 内。如果您使用 lamda 表达式和运行时异常,就会变得非常清楚。如果您使用 AOP 允许的声明式事务,使用 Spring 或 CDI/EJB 等框架,则更加清晰。
-
我对spring aop不熟悉。它可以处理嵌套事务吗?
-
Btw SQLException 不是运行时异常。我怎么不能用呢?