2016-02-01 8 views
1

Я работаю над доказательством концепции, чтобы преобразовать наш проект в приложение Spring Boot. У меня есть класс репозитория с двумя методами: сохранить и найти.Spring Boot + JPA + Обработка исключений

@Repository 
public class UserDataRepo { 
    private EntityManager em; 

    public boolean save(UserDataModel model) { 
     try { 
      UserDataModel existingModel = find(model.getTable(), model.getFieldName(); 
      model.setId(existingModel.getId()); 
      this.em.merge(model); 
      this.em.flush(); 
      return false; 
     } catch (NoResultException e) { 
      this.em.persist(model); 
      this.em.flush(); 
      return true; 
     } 
    } 

    public UserDataModel find(String table, String field) { 
     Query query = this.em.createQuery(FIND_USERDATA_STATEMENT); 
     query.setParameter("table", table); 
     query.setParameter("fieldName", field); 
     return (UserDataModel) query.getSingleResult(); // throws NoResultException 
    } 
} 

В моем Spring классе загрузки приложений, я добавил @EnableJpaRepositories, @EnableTransactionManagement. Мое приложение запускается без ошибок. Но поскольку вы можете видеть, что метод save зависит от метода find, чтобы определить, сходиться или сохраняться. Если нет записи, метод find вызывает NoResultException. То, что я наблюдаю, никогда не попадает внутрь блока catch метода save. Spring Boot просто выдает сообщение об ошибке NoResultException.

В случае слияния он работает как шарм. Таким образом, это означает, что диспетчер объектов работает нормально.

Я не знаю, что еще нужно настроить. Есть предположения?

Добавление ошибки из журналов:

org.springframework.dao.EmptyResultDataAccessException: No entity found for query; nested exception is javax.persistence.NoResultException: No entity found for query 
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:389) 
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223) 
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417) 
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) 
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) 
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
+0

Похоже, что исключение, которое вы хотите поймать, это 'org.springframework.dao.EmptyResultDataAccessException' вместо' NoResultException'. «NoResultException» вложен внутри внешнего исключения, поэтому ваш блок 'try {} catch' не увидит его – tddmonkey

+0

@MrWiggles Я изменил его, чтобы поймать EmptyResultDataAccessException, но он не попадает в блок catch. Должны ли исключения отображаться по-разному при использовании Spring Boot или настройка настойчивости с помощью Spring Boot? – Gnana

+0

Вы можете временно изменить свой блок catch на «Throwable», чтобы узнать, что такое реальное Исключение. – tddmonkey

ответ

4

Я не рекомендовал бы это поведение. Использовать getSingleResult(), как это не рекомендуется. Подробнее о том, почему never to use getSingleResult in JPA here. Вместо этого попробуйте такой запрос.

Query query = this.em.createQuery(FIND_USERDATA_STATEMENT); 
    query.setParameter("table", table); 
    query.setParameter("fieldName", field); 

    List results = query.getResultList(); 
    if (results.isEmpty()) { 
     return null; 
    } 
    else if (results.size() == 1) { 
     return results.get(0); 
    } 
    throw new NonUniqueResultException(); 
+0

Я согласен с вами и статьей, о которой вы говорили. Поскольку это производственный код, и есть другой рефакторинг, который необходимо выполнить. Но почему причина, почему Spring Boot не может каскадировать/переводить исключение и попадать внутрь блока catch? – Gnana

+1

'' 'NoResultException''' - это исключение во время выполнения, вам придется поймать его внутри метода' '' find (...) '' '. – DominicEU

4

Для простых случаев настойчивости, как это, я бы очень настоятельно рекомендую смотреть на Spring Data JPA, которая позволит вам избежать необходимости делать какой-либо из этого сложного ручного управления инерционностью. Если это не сработает для вас, я настоятельно рекомендую вам не использовать Exceptions for Logic. То есть вместо того, чтобы полагаться на исключение из неудавшегося запроса поиска, чтобы определить, нужно ли сохранять или объединять объект, я бы сначала запросил использование подсчета, чтобы определить, существует ли этот объект, а затем, в зависимости от этого результата, продолжайте с слияние или сохранение. В общем случае использование исключений в бизнес-логике считается анти-шаблоном, см.: When is it OK to use exception handling for business logic?

+0

Спасибо за предложение. Необходимо провести много рефакторинга :) – Gnana

0

Я просто добавил «throws NoResultException» к методу поиска, и он сработал. Непонятно, почему это должно быть специально добавлено в подпись при настройке приложения в Spring Boot.

Смежные вопросы