How to Handle JPA Unique Constraint Violations

How to handle JPA unique constraint violations?

How can I find out that a unique constraint was violated?

Exception are chained, you have to call getCause() recursively to get the provider specific exception (and maybe go down to the SQLException) to translate it into something your application can handle nicely for your user. The following will print the chain of exception:

for (t = e.getCause(); t != null; t = t.getCause()) {
logger.debug("Exception:" + t);
}

For the exception handling and the "translation", you could do something like what Spring does (see the various JpaDialect classes, e.g. HibernateJpaDialect to get an idea).

All this is not nice, this code won't be portable and finding what attribute(s) caused the violation won't be easy. This somehow confirms that there is no elegant and portable way to handle constraint violations in JPA.

Best way to prevent unique constraint violations with JPA

Your last solution is the right one, IMO. Search for the keyword type, and if not found, create it.

Catching the exception is not a good option because

  • it's hard to know which exception to catch and make your code portable across JPA and DB engines
  • The JPA engine will be in an undetermined state after such an exception, and you should always rollback in this case.

Note however that with this technique, you might still have two transactions searching for the same type in parallel, and then try to insert it in parallel. One of the transaction will rollback, but it will be much less frequent.

Catching constraint violations in JPA 2.0

When I insert records with a duplicate value for the link attribute, EclipseLink does not throw a EntityExistsException

Yes, and a JPA provider is not supposed to throw an EntityExistException in that case, you won't get an EntityExistException on something else than the primary key.

(...) but throws a DatabaseException, with the message explaining that the unique constraint was violated.

This is very WRONG from EclipseLink, a JPA provider should throw a PersistenceException or a subclass but certainly not a specific exception like o.e.p.e.DatabaseException. This is a bug and should be reported as such as I already mentioned in a previous answer.

This doesn't seem very usefull, as there would not be a simple, database independent, way to catch this exception. What would be the advised way to deal with this?

Same answer as above, see my previous answer.

Best practice propagating Unique Violation Exceptions to UI

Approach 1 will not work in a concurrent scenario! -- There is always a change that somebody else insert a new database record after you checked but before you added your database record. (except you use isolation level serializable, but this is highly unlikely)

So you have to handle the DB constraint violation exceptions. But I recommend to catch the database exception that indicates the unique violation and throw a more meaning full like you suggested in Approach 1.

Unique Constraint error thrown at the end of @Transactional block

The error happens in the interceptor because right before committing the transaction, Hibernate needs to flush pending changes to the database. During that flush, the database exception happens. You can flush manually by calling saveAndFlush on the repository.



Related Topics



Leave a reply



Submit