我有一个持久化类,它具有多字段唯一约束。但是定义的唯一约束对我来说是不够的,因为在那些字段中,不相等但相似的值也是唯一的。
我实现了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();
}
}
我有一个用于添加的事务服务方法,另一个用于更新。
当我运行我的测试时
但实际上是一个org.hibernate.exception。通过checkUniqueConstraint !!
抛出ConstraintViolationException为什么呢?
答案 0 :(得分:3)
问题必须在 FlushMode 中。默认情况下,Hibernate会在执行查询之前刷新实体,请参阅http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/FlushMode.html#AUTO。
您必须部分初始化新实体,将它们与会话限制的实体相关联,现在尝试执行查询。 Hibernate会话在查询之前执行flush,并且使用ConstraintViolationException失败,这是正常的。
解决方案:
答案 1 :(得分:0)
我怀疑PersistClass
中的getter或setter不是普通的get / set逻辑。
如果你的getter没有返回Hibernate传递给setter的同一个实例,那么Hibernate会刷新" dirty"交易完成后的实体。
您可以粘贴PersistClass
代码,也可以粘贴Hibernate日志来验证吗?
答案 2 :(得分:0)
如果在insert / update
之前有任何select
操作,则Hibernate将仅在save
之前刷新。默认情况下,在调用update
或select
时,Hibernate不会立即提交对数据库的更改。这是为了利用JDBC批处理来提高性能。当会话关闭,提交事务或向数据库发出选择时,Hibernate将仅刷新对数据库的更改。在select
之前进行此刷新是必要的,因为如果先前的更改没有刷新到DB,则查询结果可能不正确。
因此,您的插入/更新实际上是在find方法之前调用的对象创建/更新,并且只在{{1}}之前刷新到DB。