Вы действительно не должны пытаться это делать.Как упоминалось в другом ответе и цитировании Hibernate Docs, никакое исключение, выброшенное Hibernate, не должно рассматриваться как восстанавливаемое.Это может привести к некоторым трудностям в поиске / отладке проблем, особенно с помощью автоматической проверки на наличие ошибок в спящем режиме.
Чистый способ решить эту проблему - проверить эти ограничения перед вставкой объекта.Используйте запрос для проверки, нарушается ли ограничение базы данных.
public Object foo() {
if (!objectExists()) {
insertStuff();
return stuff();
}
// Code for loading object...
}
Я знаю, что это кажется немного болезненным, но это единственный способ, которым вы точно будете знать, какое ограничение было нарушено (вы не можетеполучить эту информацию из исключений Hibernate).Я считаю, что это самое чистое решение (по крайней мере, самое безопасное).
Если вы все еще хотите восстановиться после исключения, вам придется внести некоторые изменения в свой код.
Как уже упоминалось, вы можете управлять транзакциями вручную, но я не рекомендую этого.JTA API действительно громоздок.Кроме того, если вы используете Bean Managed Transaction (BMT), вам придется вручную создавать транзакции для каждого метода в вашем EJB, это все или ничего.
С другой стороны, вы можете реорганизовать ваши методы так,Контейнер будет использовать другую транзакцию для вашего запроса.Примерно так:
@Stateless
public class Foo {
...
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public Object foo() {
try {
entityManager.insert(stuff);
return stuff;
} catch (PersistenceException e) {
if (e.getCause() instanceof ConstraintViolationException) {
// At this point the transaction has been rolled-backed.
// Return null or use some other way to indicate a constrain
// violation
return null;
}
throw e;
}
}
// Method extracted from foo() for loading the object.
public Object load() {
...
}
}
// On another EJB
@EJB
private Foo fooBean;
public Object doSomething() {
Object foo = fooBean.insert();
if (foo == null) {
return fooBean.load();
}
return foo;
}
Когда вы вызываете foo (), текущая транзакция (T1) будет приостановлена, и контейнер создаст новую (T2).При возникновении ошибки, T2 будет откат, и T1 будет восстановлен.Когда вызывается load (), он будет использовать T1 (который все еще активен).
Надеюсь, это поможет!