任何RuntimeException都会触发回滚,任何已检查的Exception都不会
未经核实的例外:
- 表示程序中的缺陷(错误) - 通常是无效的参数 传递给非私有方法。至 引用Java编程 语言,由Gosling,Arnold和 Holmes:“未经检查的运行时异常 通常表示条件 说,反映你的错误 程序的逻辑并不可能 从跑步中合理地恢复 时间“。
- 是RuntimeException的子类,通常是实现的 使用抛出:IllegalArgumentException,NullPointerException异常, 或IllegalStateException异常
- 方法没有义务为未经检查的例外建立策略 由它的实现抛出(他们几乎总是不这样做)
已检查的例外:
- 表示在即时控制之外的区域中的无效条件 程序(用户输入无效, 数据库问题,网络中断, 缺席文件)
- 是Exception的子类
- 方法有义务为所有已检查的异常建立策略 由它的实现抛出(或者 将检查的异常进一步传递 堆栈,或以某种方式处理它)
如果在我的业务逻辑中发现问题并且我想要回滚更改,我必须抛出一个新的RuntimeException?它不是真正的RuntimeException(未经检查的异常),因为我已经在逻辑中识别出它。或许我误解了这些概念?
我真正的问题,在我的@Transactional服务方法中回滚交易的最佳做法是什么?
答案 0 :(得分:12)
如果您使用的是已检查的例外,只需将其添加到rollbackFor
注释的@Transactional
属性中即可。
@Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class })
public void method() throws MyInvalidUserException, MyApplicationException {
...
...
}
等
org.life.java的答案也可以。如果您想将程序化事务管理混合到您的声明性事务中,或者将其严格声明,那么这是一个学术决策。
答案 1 :(得分:7)
从内部以编程方式回滚:
@Transactional
public void commit() {
try {
// some business logic...
} catch (ConstraintViolationException e) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
或标记回滚的异常并从调用者处理它:
@Transactional(rollBackFor = TransactionException.class)
public void commit() throws ConstraintViolationException{
try {
// some business logic...
} catch (ConstraintViolationException e) {
// handle the exception
// re-throw for rollback
new TransactionException(e);
}
}
public void doCommit(){
try {
commit()
} catch (TransactionException e){
// do nothing as already handled
}
}
我更喜欢前者,因为它使代码更简单,但根据Spring文档它是discouraged:
如果您绝对需要,可以使用程序化回滚,但是 它的用法在实现基于POJO的清洁方面过得很快 架构。
答案 2 :(得分:4)
应该是
@Transactional
public void method () throws YourCustomException {
try{
//logic
}catch(Exception ex){
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
throw(new YourCustomException(ex.getMessage()));
}
}
答案 3 :(得分:2)
我认为可以肯定地说,应该检查哪些例外有不同的意见。例如,请考虑Introduction to the Spring Framework的摘录:
Spring数据访问异常 层次结构基于未选中 (运行时)异常。工作过 我在几个项目上使用Spring 越来越相信这是 正确的决定。
通常不会出现数据访问异常 恢复。例如,如果我们做不到 连接到数据库,特别是 业务对象不太可能 解决问题。一 潜在的例外是乐观的 锁定违规,但不是全部 应用程序使用乐观锁定。 被迫写作通常很糟糕 用于捕获致命异常的代码 不能明智地处理。让 它们传播到顶级处理程序 就像servlet或EJB容器一样 通常更合适。全春天 数据访问异常是子类 DataAccessException,如果我们这样做 选择捕获所有Spring数据访问 例外情况,我们可以很容易地这样做。
请注意,如果我们确实想要恢复 来自未经检查的数据访问 例外,我们仍然可以这样做。我们可以 编写代码只处理 可恢复的条件。例如,如果 我们认为这只是乐观的 锁定违规是可以恢复的,我们 可以在Spring DAO中编写代码 如下:
尝试{// do work} catch (OptimisticLockingFailureException ex) {//我对此感兴趣}如果 Spring数据访问异常是 检查过,我们需要写一下 以下代码。请注意,我们可以 无论如何选择写这个:
尝试{// do work} catch (OptimisticLockingFailureException ex) {//我对此感兴趣 (DataAccessException ex){//致命; 只是重新抛出它}一个潜力 反对第一个例子 - 那个 编译器无法强制执行 潜在可恢复的例外 - 也适用于第二个。因为我们被迫抓住基地 异常(DataAccessException),. 编译器不会强制检查 子类 (OptimisticLockingFailureException)。 所以编译器会迫使我们这样做 编写代码来处理不可恢复的 问题,但没有提供帮助 迫使我们处理 可恢复的问题。
Spring使用未经检查的数据访问 例外情况与例外情况一致 许多 - 可能是最多 - 成功 持久性框架。 (的确如此 部分受到JDO的启发。)JDBC就是 要使用的少数数据访问API之一 检查异常。 TopLink和JDO, 例如,使用未经检查的异常 只。 Hibernate切换自 检查未经检查的例外情况 版本3.
数据访问异常显然超出了程序的直接控制范围,因此根据javapractices,应该检查它们。但春源的人不同。我相信他们的判断不仅仅是javapractices。
因此,我认为抛出未经检查的异常以指示应该回滚事务没有错。当然,您也可以使用已检查的异常,并配置方面以回滚它们。 (详见Affe的回答)
答案 4 :(得分:2)
遇到这个网址,用于处理已检查的&未经检查的例外,管理交易: 这不是注释驱动的方法,但它很好。