hibernate 4处理唯一索引异常

时间:2016-01-06 23:24:59

标签: java mysql hibernate constraints

我有一个基于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;
 }

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

Propagation.REQUIRES_NEW does not create a new transaction in Spring with JPA

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

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

}

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

  1. 开始大型外部交易
  2. 启动新的嵌套事务,尝试插入记录。
  3. 如果嵌套事务失败,它将回滚,但外部事务仍将运行。
  4. 如果第一个嵌套事务失败,则启动新的嵌套事务并插入包含新数据的记录,这将阻止抛出ConstaintViolationException。
  5. 因此,在这种情况下,我们创建一个类:

    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();
       }
     }
    }
    

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

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

    我不喜欢它。但这种方法有效,我今天检查过。

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