2012-12-30 29 views
2

我有一个持有多字段唯一约束的类。但是对于我来说,定义的唯一约束是不够的,因为一个领域不相等但相似的值也是唯一的。关于SELECT查询的Hibernate ConstraintViolationException

我执行checkUniqueConstraint方法。 在添加和更新DAO类的方法中,我在添加或更新持久对象之前调用checkUniqueConstraint

checkUniqueConstraint方法只是运行一个SELECT查询来找到类似于输入的对象,并抛出一个检查异常,其中找到一些。

public class PersistClassDao {  
public void checkUniqueConstraint(PersistClass persistObject) throws DuplicateEntityException { 
    /** 
    * creating a query string that find persist objects similar to input parameter. 
    **/ 
    try { 
     PersistClass result = (PersistClass) query.uniqueResult(); 
     if(result != null && (persistObject.getId() == null || persistObject.getId() != result.getId())){ 
      throw new DuplicateEntityException(exceptionMessage, ""); 
     } 
    } catch (NonUniqueResultException e) { 
     throw new DuplicateEntityException(exceptionMessage); 
    } 
} 

public long add(/* field of new persistObject*/) throws DuplicateEntityException { 
    //creates a transisent instance of persistObject 
    PersistClass newObject = getPersistClass(/* field of new persistObject*/); 
    checkUniqueConstraint(newObject); 
    try { 
     getCurrentSession().save(newObject); 
     getCurrentSession().flush(); 
     return newObject.getId(); 
    } catch (ConstraintViolationException e) { 
     throw new DuplicateEntityException(); 
    } 
} 

我有一个transactionl服务mehod添加和另一个更新。

当我运行我的测试

  • 首先加2个persistObjects(通过服务方法)。
  • 然后更新一个(通过服务方法)他们,使类似于其他
  • 我希望DuplicatException抛出

但真的org.hibernate.exception。通过checkUniqueConstraint抛出ConstraintViolationException!

为什么?

+0

向我们显示导致异常的代码和异常堆栈跟踪。你说你**通过服务方法更新**一个对象,但服务方法**添加**一个新对象。 –

+1

很难说这个问题是什么,但从我的角度来看,你正在努力实现一些不可取的事情。我真的建议你考虑通过你的数据库模型,并试图让你的约束进入数据库,而不是用Java解决它。 – sorencito

+0

@JBNizet你是对的,这是一个_API_ _defect_,但实际上我们的服务方法更新现有的持久对象(通过获取持久对象ID作为输入参数) – mjafari

回答

0

我怀疑你的PersistClass里面的获取者或设置者不是纯粹的get/set逻辑。 如果你的getter没有返回Hibernate传递给setter的同一个实例,Hibernate将在事务完成时刷新“dirty”实体。

你可以粘贴你的PersistClass代码,也许Hibernate日志来验证?

+0

是的。我有一对非纯粹的getter setter方法,但是这些对应于一个瞬态场。 – mjafari

3

问题必须在FlushMode。默认情况下,Hibernate会在执行查询之前刷新实体,请参阅http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/FlushMode.html#AUTO

您必须部分初始化新实体,并将它们与会话绑定的实体关联,然后尝试执行查询。 Hibernate会话在查询之前执行刷新,并且以ConstraintViolationException失败,这是正常的。

解决方案:

  1. 变化FlushModeCOMMIT在为整个应用程序CFG文件
  2. 修改只是由session.setFlushMode(FlushMode.COMMIT)的单个会话
  3. 您可以通过调用query.setFlushMode(FlushMode.COMMIT)将更改的影响缩小到单个查询。
0

Hibernate才刷新之前select如果存在select之前的任何insert/update操作。默认情况下,当调用saveupdate时,Hibernate不会立即向DB提交更改。这是为了利用JDBC批处理来提高性能。 Hibernate只会在会话为已关闭,事务提交选择发布到数据库时刷新对数据库的更改。在select之前进行刷新是必要的,因为如果没有将先前的更改刷新到数据库,则查询结果可能不正确。

因此,您的插入/更新实际上是在find方法之前调用的对象创建/更新,并且仅在select之前刷新到DB。