【发布时间】:2015-02-26 18:47:31
【问题描述】:
我们面临类似于以下的情况:
@ApplicationException(rollback = true)
class UniqueConstraintViolated extends RuntimeException { ... }
interface GenericStorageService {
void insert(Object ety); // throws UniqueConstraintViolation
}
class ServiceA {
@Inject GenericStorageService store;
void insert(A ety) {
someSideEffect();
store.insert(ety);
someOtherSideEffect();
}
}
class ServiceB {
@Inject GenericStorageService store;
void insertIfNotYetPresent(B ety) {
try {
someSideEffect();
store.insert(ety);
someOtherSideEffect();
} catch (UniqueConstraintViolation e) {
// that's totally ok
}
}
}
在这种情况下,
- 请求插入一些先前插入的
A是一个实际的用户错误。无法以有意义的方式提交事务。 - 请求插入一些以前存在的
B是不是错误。只需确认上述B的存在,就可以安全地提交事务。特别是,无论给定的B之前是否插入,都需要提交副作用。
根据(我对 EJB 规范的理解),上述代码将触发在任何一种情况下的回滚,不会导致所需的语义。
据我了解,EJB 为我们提供了以下选择:
- 用
rollback = false装饰UniqueConstraintViolated,在ServiceA中手动捕获它并通过程序化事务控制回滚事务。 - 将
UniqueConstraintViolated拆分为两个兄弟UniqueConstraintViolatedThatNeedsRollback和UniqueConstraintViolatedThatNeedsNoRollback。此外,将GenericStorageService的insert方法替换为insertWithRollbackingUniqueConstraint和insertWithNonRollbackingUniqueConstraint两个变体。 - 吸吧。
选项 1 是不可取的,因为大多数服务与ServiceA 的类型相同,所以rollback = true 是更准确的选择。此外,它还破坏了声明式事务控制的优雅。
选项 2 是不可取的,因为对于GenericStorageService,这两种情况实际上是相同的。在这个层面上的区别是没有意义的。此外,UniqueConstraintViolated 并不是唯一需要区分的例外......我们会遭受组合爆炸的影响。
选项 3 无需进一步解释。
这给我留下了最后一个问题:
什么是选项 4?
【问题讨论】:
标签: java jakarta-ee transactions ejb