hibernate 4处理唯一索引异常



我有一个基于hibernate 4的系统。我在一个表中有一个唯一的约束,需要用以下方式处理它:

try{
    getMyService().create(myobj);
}catch(PersistenceException p){
  //constraint fails
    myobj.setConstraintColumn("new non unique value");
   getMyService().create(myobj);//should save it
}

不幸的是,我无法改变系统的设计,所以我只需要这样想。

编辑

我得到以下异常:

org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs)

创建方法代码:

 public E create(E entity) {
        entityManager.persist(entity);
        entityManager.flush();
        entityManager.refresh(entity);
        return entity;
 }

不清楚您的事务边界在哪里。当抛出异常时,您需要:1) 确保第一个事务已关闭(应该关闭,但不确定-看看是否有嵌套事务单独尝试#2)2) 在能够再次持久化/刷新(并随后提交)之前,先开始一个新事务。

我终于解决了这个问题。所以,让我逐一解释。首先,看看

Propagation.REQUIRES_NEW不会在Spring中使用JPA 创建新事务

然后,例如,我们有一个类和方法,如:

public class MyClass{
   @Transactional
   public void myMethod(){
      ....
   }
}

因此,首先让我们考虑myMethod完全在它自己的事务中,因为事务是基于AOP的,它将在适当的方面启动时提交,但只有在方法完成、抛出异常等之后。因此,我们不能部分提交、部分回滚、不完全回滚等。因此,我们需要做以下工作:

  1. 启动大额外部交易
  2. 启动一个新的嵌套事务,尝试插入一条记录
  3. 如果嵌套事务将失败,它将被回滚,但外部事务仍将运行
  4. 如果第一个嵌套事务失败,那么启动一个新的嵌套事务并插入一个包含新数据的记录,这将防止引发ConstaintViolationException

因此,在这种情况下,我们创建一个类:

public class ServiceHelper{
    @Transational(proparation = **Propagation.REQUIRED_NEW**)
    public void tryConstraint throws MyConstraintException{
        try{
           //insert
        }catch(ConstraintViolationException e){
           throw new MyConstraintException(e);
        }catch(Exception ex){
           throw new Exception(ex);
        }
    }
    @Transational(proparation = **Propagation.REQUIRED_NEW**)
    public void insertWithNoConflict throws Exception {
        //Set new data
        //insert, if still CVE or anything other, just throw it , or leave it for unchecked exceptions then
    }

}

以及我们的服务:

public class MyService{
@Autowired
private ServiceHelper serviceHelper;
@Transactional(propagation = **Propagation.REGUIRED_NEW**)
public void createWithCheck(){
   try{
      serviceHelper.tryConstraint();
   }catch(MyConstraintException e){
       serviceHelper.insertWithNoConflict();
   }
 }
}

但仍然存在一种奇怪的情况,因为我需要在ServiceHelper中使用MyService方法来创建记录,但我无法在那里获得它们,因为这会导致循环注入,所以我必须通过服务工厂获得它们,比如:

MyService service = (MyService)ServicesFactory.getInstance().getBean(MyService.BEAN_ID)

我不喜欢。但这种方法有效,我今天检查了一下。

我们应该知道两件事:首先,我们不能对方法内部的事务做任何事情,我们不能在那里启动任何新的事务,等等。事务上下文与方法完全相关,在方法结束之前它仍然存在。第二件事是required_new,当我们从同一代理类的方法启动方法时,它不起作用。

最新更新