使用Spring框架实现以下场景
@Transactional
processRequest() {
createOrder();
}
@Transactional
createOrder() {
...
try {
saveRow();
} catch (SaveNotAllowedException e) {
// Handle the expected problem
...
log.info("Save was not allowed...");
// We have to do this otherwise we get UnexpectedRollbackException
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Transactional(rollbackFor = SaveNotAllowedException.class)
saveRow() throws SaveNotAllowedException {
// Updating row in database is not allowed because of some business condition
throw new SaveNotAllowedException();
}
请注意:方法是公共的,在不同的类中。省略了参数和不相关的东西。SaveNotAllowedException被选中异常。
在saveRow方法上,我声明我希望对检查的异常进行回滚。在createOrder方法中,我捕获该异常并执行相关工作来处理该情况。但由于这是一个预期的回滚,我希望Spring也将其视为预期的回滚,并让我尝试一下。
有些人认为这是一个特例。据我理解,这是完全相反的,这实际上是通常的情况。拥有业务代码,调用某个方法,抛出业务异常,并检查它,以预期的方式改变行为,这在我看来是相当标准的。那么,为什么我必须执行一个特殊步骤,调用晦涩的API setRollbackOnly()来避免崩溃呢?
预期的异常被视为意外,因为AOP代理只有在从最后一个@transactional
方法返回时才会做出决定,该方法创建了事务。代理必须看到正在传播的异常并为其声明了回滚。
为了防止ExpectiontedrollbackException,检查的异常必须在事务之外的代码中捕获,即在代理关闭事务后调用的代码中捕获。
在最初的问题示例中,事务在processRequest()上启动,它是从框架调用的,显然不能抛出任何检查过的异常。因此,在这种情况下,必须在之前捕获异常。
@Transactional
processRequest() {
...
try {
createOrder();
} catch (SaveNotAllowedException e) {
// Handle the expected problem
...
log.info("Save was not allowed...");
}
try {
backupOrder();
} catch (AnotherException e) {
...
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW,
rollbackFor = SaveNotAllowedException.class)
createOrder() throws SaveNotAllowedException {
...
saveRow();
}
@Transactional(propagation = Propagation.REQUIRES_NEW,
rollbackFor = AnotherException.class)
backupOrder() throws AnotherException {
...
}
@Transactional
saveRow() throws SaveNotAllowedException {
// Updating row in database is not allowed because of some business condition
throw new SaveNotAllowedException();
}
从processRequest()中删除@transaction
。使用@transactional(rollbackFor=savenotallowedexception.class)
在createorder()上声明回滚。在processRequest()中捕获异常。
processRequest() {
...
try {
createOrder();
} catch (SaveNotAllowedException e) {
// Handle the expected problem
...
log.info("Save was not allowed...");
}
try {
backupOrder();
} catch (AnotherException e) {
...
}
}
@Transactional(rollbackFor = SaveNotAllowedException.class)
createOrder() throws SaveNotAllowedException {
...
saveRow();
}
@Transactional(rollbackFor = AnotherException.class)
backupOrder() throws AnotherException {
...
}
@Transactional
saveRow() throws SaveNotAllowedException {
// Updating row in database is not allowed because of some business condition
throw new SaveNotAllowedException();
}
但是解决方案1和2可能不是你想要的。您可能希望将整个流程(createOrder()和backupOrder())放在一个事务中,而不是创建新的流程。另一种方法是创建另一个从processRequest()调用的事务性助手服务方法,该方法将在一个事务中调用createOrder和backupOrder。我们需要创建的helper方法与我们拥有的事务组合一样多。
令人遗憾的是,Spring文档中没有提到这些复杂的细节。最接近的信息是http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html#tx-propagation--这是必需的,但需要更详细的说明或至少需要重新措辞。
问题内容: 为什么即使该类中没有抽象方法,也将类声明为抽象? 问题答案: 这是因为它遵循模板方法设计模式。这些方法具有返回HTTP 405 未实现方法 错误的所有默认行为。如果所有这些方法都是抽象的,那么即使您的业务需求根本不需要它们,也将不得不覆盖所有这些方法。这只会导致样板代码和不确定/不直观的行为。
我正在讨论以下问题:使用Java 8的可选和stream::FlatMap并希望向自定义的添加一个方法,然后检查它是否工作。 更准确地说,我希望向我的添加一个。如果不存在值,则返回一个空流,如果存在,则返回一个包含单个元素的流。 但是,我得出的结论是,声明为final。 为什么会这样呢?有一些类没有声明为final,我个人认为这里没有理由声明final。 作为第二个问题,为什么不是所有的方法都是f
问题内容: 为什么将Java常量声明为static? 在此我了解使用final吗?购买为什么它必须是静态的?为什么它应该是类变量,而不是实例变量? 问题答案: 如果它可以随类的实例而变化,那么显然它不是 常数 。为的每个实例获得不同的pi值意味着什么(甚至不允许构造实例)?还是每个实例的大小写不区分大小写?
变量被编译器声明为const,导致无法编译
我的RMI服务器接口声明了一个方法foo(),该方法被声明为引发RemoteException和Exception,如下所示: 服务器实现为: 我的客户端在服务器上调用foo: 现在,当我运行客户端时,我得到: 从java类型的foo()中获取异常。rmi。异常异常:未声明的检查异常;嵌套的例外是:java。伊奥。InterruptedIOException:操作超时 Java文档是这样说的。rm
问题内容: 将接口声明为抽象有什么意义?接口方法也是如此。有什么意义吗? 例如。 问题答案: 您在哪里遇到过已发布的代码块,任何旧的Java代码库? 这就是 JLS不得不说: 9.1.1.1抽象接口: 每个接口都是隐式抽象的。该修饰符已过时,不应在新程序中使用。 9.4抽象方法声明: 为了与Java平台的较早版本兼容,出于风格考虑,允许但不鼓励为接口中声明的方法冗余地指定abstract修饰符。