在Spring 3/Hibernate中回滚事务的最佳实践

Cor*_*rey 19 java spring hibernate transactions spring-mvc

引用Spring文档:

任何RuntimeException都会触发回滚,任何已检查的Exception都不会

引用javapractices.com

未经检查的例外情况:

  • 表示程序中的缺陷(错误) - 通常是传递给非私有方法的无效参数.引用来自Gosling,Arnold和Holmes的Java编程语言:"未经检查的运行时异常表示一般来说,它反映了程序逻辑中的错误,并且无法在运行时合理地恢复."
  • 是RuntimeException的子类,通常使用IllegalArgumentException,NullPointerException或IllegalStateException实现
  • 方法没有义务为其实现抛出的未经检查的异常建立策略(并且它们几乎总是不这样做)

检查异常:

  • 代表程序直接控制范围之外的区域中的无效条件(无效的用户输入,数据库问题,网络中断,缺少文件)
  • 是Exception的子类
  • 方法有义务为其实现抛出的所有已检查异常建立策略(将已检查的异常传递到堆栈中,或以某种方式处理它)

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

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

Aff*_*ffe 12

如果您使用的是已检查的例外,则只需将它们添加到注释的rollbackFor属性中即可@Transactional.

@Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class })
public void method() throws MyInvalidUserException,  MyApplicationException { 
    ... 
    ... 
}
Run Code Online (Sandbox Code Playgroud)

等等

org.life.java的答案也很好.如果您希望将程序化事务管理混合到声明性事务中或将其严格声明,则这是一个学术决策.


Tom*_*asz 7

从内部以编程方式回滚:

@Transactional
public void commit() {
  try {
    // some business logic...
  } catch (ConstraintViolationException e) {
    // trigger rollback programmatically
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}
Run Code Online (Sandbox Code Playgroud)

或标记回滚的异常并从调用者处理它:

@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
  }
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢前者,因为它使代码更简单,但根据Spring文档,它是不鼓励的:

如果您绝对需要程序化回滚,则可以使用程序化回滚,但它的使用方式可以实现基于POJO的简洁体系结构.