3

我有一个带有多字段唯一约束的持久类。但是定义的唯一约束对我来说是不够的,因为在其中一个字段不相等但相似的值也是唯一的。

我实现了一个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();
    }
}

我有一个用于添加的事务服务方法和另一个用于更新的方法。

当我运行我的测试时

  • 首先添加2个persistObjects(通过服务方法)。
  • 然后更新其中一个(通过服务方法),使其与另一个相似
  • 我希望抛出 DuplicatException

但实际上是 org.hibernate.exception。通过 checkUniqueConstraint 抛出 ConstraintViolationException!

为什么?

4

3 回答 3

4

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

您必须已部分初始化新实体,将它们与会话绑定的实体相关联,现在尝试进行查询。Hibernate 会话在查询之前执行刷新并失败并出现 ConstraintViolationException,这没关系。

解决方案:

  1. 在整个应用程序的 cfg 文件中将 FlushMode更改为COMMIT
  2. 通过session.setFlushMode(FlushMode.COMMIT)只修改一个会话或
  3. 您可以通过调用query.setFlushMode(FlushMode.COMMIT)将更改的影响缩小到单个查询。
于 2013-01-15T08:53:41.140 回答
1

只有在. select_ 默认情况下,当调用或时,Hibernate 不会立即将更改提交到数据库。这是为了利用 JDBC 批处理来提高性能。Hibernate 只会在会话关闭事务提交或向数据库发出选择时刷新对数据库的更改。之前的刷新是必要的,因为如果没有将先前的更改刷新到数据库,查询结果可能不正确。insert / updateselectsaveupdateselect

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

于 2017-12-08T10:55:57.120 回答
0

我怀疑你里面的 getter 或 setterPersistClass不是简单的 get/set 逻辑。如果您的 getter 没有返回 Hibernate 传递给 setter 的相同实例,Hibernate 将在事务完成时刷新“脏”实体。

你能粘贴你的PersistClass代码,也许是 Hibernate 日志来验证它吗?

于 2012-12-30T13:14:05.493 回答