问题
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:
- change FlushMode to COMMIT in cfg file for the entire application,
- modify just a single session by session.setFlushMode(FlushMode.COMMIT) or
- 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