在 Spring 3/Hibernate 中回滚事务的最佳做法

参考弹簧文档

任何运行时异常都会触发回滚,任何选中的异常都不会

引用 javapractices.com

未选中的例外 :

  • 表示程序中的缺陷(错误) - 通常无效的参数传递给非私有方法。引用 Gosling、Arnold 和 Holmes 的《The Java Programming Language》一文:“未经检查的运行时异常通常表示反映程序逻辑中的错误且无法在运行时合理恢复的条件。
  • 是 RuntimeException 的子类,通常使用 IllegalArgumentException、NullPointerException 或 IllegalStateException 实现。
  • 一个方法没有义务为其实现引发的未经检查的异常建立策略(他们几乎总是不这样做)

已检查的例外 :

  • 表示程序直接控制范围之外的区域中的无效条件(无效用户输入、数据库问题、网络中断、文件缺失)
  • 是异常的子类
  • 一个方法有义务为其实现引发的所有已检查异常建立策略(要么将已检查的异常进一步向上传递堆栈,要么以某种方式处理它)

如果在我的业务逻辑期间我发现了一个问题,并且我想回滚更改,我必须抛出一个新的 RuntimeException?它不是真正的运行时异常(未经检查的异常),因为我已经在逻辑中识别了它。或者也许我误解了这些概念?

我真正的问题是,在我的@Transactional服务方法中回滚事务的最佳实践是什么?


答案 1

如果您使用的是已检验的异常,则只需将它们添加到注释的属性中即可。rollbackFor@Transactional

@Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class })
public void method() throws MyInvalidUserException,  MyApplicationException { 
    ... 
    ... 
}

等。

org.life.java的答案也很好。如果要将编程事务管理混合到声明性事务中或保持严格声明性,这是一个学术决策。


答案 2

以编程方式从以下内部回滚:

@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文档,它不鼓励

如果您绝对需要编程回滚,则可以使用它,但是与实现基于POJO的干净架构相比,它的使用却不菲。


推荐