Подтвердить что ты не робот

Как я могу исключить исключение нарушения ограничений из 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 не переносимо, но мне нужно что-то начать. Исключения никогда не попадают. Любые предложения?

4b9b3361

Ответ 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 (...).

Внутри этого метода вы можете поймать исключения!