Как я могу исключить исключение нарушения ограничений из EclipseLink?
Я использую EclipseLink в своем веб-приложении, и мне тяжело изящно ловить и обрабатывать Исключения, которые он генерирует. Я вижу из этой темы, что похоже на аналогичную проблему, но я не вижу, как ее можно обойти или исправить.
Мой код выглядит следующим образом:
public void persist(Category category) {
try {
utx.begin();
em.persist(category);
utx.commit();
} catch (RollbackException ex) {
// Log something
} catch (HeuristicMixedException ex) {
// Log something
} catch (HeuristicRollbackException ex) {
// Log something
} catch (SecurityException ex) {
// Log something
} catch (IllegalStateException ex) {
// Log something
} catch (NotSupportedException ex) {
// Log something
} catch (SystemException ex) {
// Log something
}
}
Когда persist() вызывается с сущностью, которая нарушает ограничение уникальности, я получаю взрыв исключений, которые пойманы и регистрируются контейнером.
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement
was aborted because it would have caused a duplicate key value in a unique or
primary key constraint or unique index identified by 'SQL110911125638570'
defined on 'CATEGORY'.
Error Code: -1
(etc)
Я пробовал следующее:
try {
cc.persist(newCategory);
} catch (PersistenceException eee) {
// Never gets here
System.out.println("MaintCategory.doNewCateogry(): caught: " + eee);
} catch (DatabaseException dbe) {
// Never gets here neither
System.out.println("MaintCategory.doNewCateogry(): caught: " + dbe);
}
Я понимаю, что использование DataBaseException не переносимо, но мне нужно что-то начать. Исключения никогда не попадают. Любые предложения?
Ответы
Ответ 1
Похоже, я больше не буду заниматься этим вопросом, поэтому я опубликую свою работу и оставлю это на этом. Ряд поисковых запросов в Интернете не нашел ничего полезного. Я бы подумал, что это случай с учебниками, но ни один из моих учебных пособий не охватывает его.
Как выясняется в этом условии с EclipseLink, исключение, которое вы можете поймать, когда нарушение SQL нарушено, - это RollBackException, которое является результатом em.commit() звонок. Поэтому я изменил свой метод persist следующим образом:
public void persist(Category category) throws EntityExistsException {
try {
utx.begin();
em.persist(category);
utx.commit();
} catch (RollbackException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
throw new EntityExistsException(ex);
} catch (HeuristicMixedException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
} catch (HeuristicRollbackException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalStateException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
} catch (NotSupportedException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
} catch (SystemException ex) {
Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
}
}
Таким образом, вызывающий объект ловит EntityExistsException и принимает соответствующие меры. Журнал по-прежнему заполняется внутренними исключениями, но позже его можно отключить.
Я понимаю, что это немного злоупотребляет намерением EntityExistsException, который обычно используется только при повторном использовании поля идентификатора объекта, но для целей пользовательского приложения он не имеет значения.
Если у кого-то есть лучший подход, напишите новый ответ или комментарий.
Ответ 2
EclipseLink должен бросать либо исключение PersitenceException, либо исключение RollbackException в зависимости от среды и порядка операций, которые вы вызываете в EntityManager.
Каков уровень ведения журнала? Вероятно, вы видите эти исключения, занесенные в журнал EclipseLink, но только выбрасываемые как причины исключения RollbackException.
Вы можете отключить ведение журнала исключений с помощью свойства PU, но для целей диагностики обычно лучше разрешить EclipseLink регистрировать исключения.
Ответ 3
Я использую Spring Boot 1.1.9 + EclipseLink 2.5.2. Это единственный способ поймать ConstraintViolationException. Обратите внимание, что my handleError(ConstraintViolationException)
- очень простая реализация, которая возвращает первое обнаруженное нарушение.
Обратите внимание, что этот код также требовался, когда я переключился на Hibernate 4.3.7 и Hibernate Validator 5.1.3.
Кажется, что добавление PersistenceExceptionTranslationPostProcessor exceptionTranslation()
к моему классу JavaConfig настойчивости также не имеет эффекта.
import javax.persistence.RollbackException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
class GlobalExceptionHandler
{
@ExceptionHandler(TransactionSystemException.class)
public ResponseEntity<Object> handleError(final TransactionSystemException tse)
{
if(tse.getCause() != null && tse.getCause() instanceof RollbackException)
{
final RollbackException re = (RollbackException) tse.getCause();
if(re.getCause() != null && re.getCause() instanceof ConstraintViolationException)
{
return handleError((ConstraintViolationException) re.getCause());
}
}
throw tse;
}
@ExceptionHandler(ConstraintViolationException.class)
@SuppressWarnings("unused")
public ResponseEntity<Object> handleError(final ConstraintViolationException cve)
{
for(final ConstraintViolation<?> v : cve.getConstraintViolations())
{
return new ResponseEntity<Object>(new Object()
{
public String getErrorCode()
{
return "VALIDATION_ERROR";
}
public String getMessage()
{
return v.getMessage();
}
}, HttpStatus.BAD_REQUEST);
}
throw cve;
}
}
Ответ 4
Я использую это.
if (!ejbGuardia.findByPkCompuestaSiExiste(bean.getSipreTmpGuardiaPK())) {
ejbGuardia.persist(bean);
showMessage(ConstantesUtil.MENSAJE_RESPUESTA_CORRECTA, SEVERITY_INFO);
} else {
showMessage("Excel : El registro ya existe. (" + bean.toString() + ") ", SEVERITY_ERROR);
}
и моя функция сверху:
public boolean findByPkCompuestaSiExiste(Object clasePkHija) throws ClassNotFoundException {
if (null != em.find(this.clazz, clasePkHija)) {
return true;
}
return false;
}
С этим мне не нужно программировать валидацию для каждого Persist, ее общего в моих классах DAO.
Ответ 5
Измените свой persistence.xml, добавив следующее свойство:
свойство name= "eclipselink.exception-handler" value = "your.own.package.path.YourOwnExceptionHandler"
Теперь создайте класс YourOwnExceptionHandler (в правильном пакете). Для этого требуется реализовать org.eclipse.persistence.exceptions.ExceptionHandler.
Создайте конструктор non argument и требуемый метод handleException (...).
Внутри этого метода вы можете поймать исключения!