Hibernate ConstraintViolationException on SELECT query

大城市里の小女人 提交于 2019-12-12 10:09:39

问题


I have a Persistent Class with multi-field unique constraint on it. But defined unique constraint is not sufficient for me because on one those field non-equal but similar values are unique too.

I implement a checkUniqueConstraint method. In add and update methods of DAO class, I call checkUniqueConstraint before adding or updating persist object.

checkUniqueConstraint method just run a SELECT query to find object similar to input and throw a check Exception where find some ones.

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

I have a transactionl service mehod for add and another for update.

When I run my test that

  • First add 2 persistObjects (through service method).
  • Then update one (through service method) them so that be similar to the other
  • I expect that DuplicatException be thrown

But really a org.hibernate.exception. ConstraintViolationException thrown through checkUniqueConstraint!!

Why?


回答1:


The problem must be in FlushMode. Hibernate by default flushes entities before executing queries, see http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/FlushMode.html#AUTO.

You must have partially initialized new entities, associated them with the session-bounded ones and now try to do the query. Hibernate session executes flush just before the query and fails with ConstraintViolationException, which is OK.

Solution:

  1. change FlushMode to COMMIT in cfg file for the entire application,
  2. modify just a single session by session.setFlushMode(FlushMode.COMMIT) or
  3. you can narrow the impact of the change down to the single Query by calling query.setFlushMode(FlushMode.COMMIT).



回答2:


I suspect the getters or setters inside your PersistClass are not plain get/set logic. If your getter doesn't return the same instance that Hibernate passed to the setter, Hibernate will flush the "dirty" entity upon transaction completion.

Can you paste your PersistClass code, and maybe the Hibernate logs to validate that?




回答3:


Hibernate will only flush before select if there is any insert / update operation before the select. By default, Hibernate does not immediately commit changes to the DB when save or update is called. This is to take advantage of JDBC batching to improve performance. Hibernate will only flush changes to the db when session is closed, transaction is committed or a select is issued to the DB. This flush before select is necessary because without the prior changes being flushed to the DB, the query result might not be correct.

So your insert/update is actually a object creation/updation being called before the find method, and is only flushed down to the DB prior to the select.



来源:https://stackoverflow.com/questions/14090386/hibernate-constraintviolationexception-on-select-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!