2014-01-08 1 views
3

Я работаю над проектом с использованием Spring Data-JPA. Мне нужно обрабатывать некоторые исключения в вызовах метода JpaRepository.Обработка данных об исключении весны

В нижеследующем коде мне нужно перехватить ошибки первичного ключа, но я не могу поймать исключение напрямую. В моем случае, когда возникает исключение такого рода, исключение UnexpectedRollbackException выбрано уровнем репозитория (JpaRepository). Мне нужно искать внутри этого объекта исключения, чтобы определить, в чем причина проблемы.

Мне интересно, есть ли более «изящный» способ достичь этого.

public Phone insert(Phone phone) throws BusinessException { 
    Phone result = null; 
    try{ 
     result = phoneRepository.save(phone); 
    } 
    catch(UnexpectedRollbackException ex){ 
     if((ex.getCause() != null && ex.getCause() instanceof RollbackException) && 
      (ex.getCause().getCause() != null && ex.getCause().getCause() instanceof PersistenceException) && 
      (ex.getCause().getCause().getCause() != null && ex.getCause().getCause().getCause() instanceof ConstraintViolationException)){ 
       throw new BusinessException("constraint violation", ex); 
     } 
    } 
    catch(Exception ex){ 
     throw new OuvidorNegocioException("unknown error", ex); 
    }  
    return result; 
} 

Спасибо!

UPDATE:

код ниже, кажется, гораздо лучше.

public Phone insert(Phone phone) throws BusinessException { 
    Phone result = null; 
    try{ 
     result = phoneRepository.save(phone); 
    } 
    catch(UnexpectedRollbackException ex){ 
     if(ex.getMostSpecificCause() instanceof SQLIntegrityConstraintViolationException){ 
       throw new BusinessException("constraint violation", ex); 
     } 
    } 
    catch(Exception ex){ 
     throw new OuvidorNegocioException("unknown error", ex); 
    }  
    return result; 
} 
+4

Я не согласен с этим подходом. Пусть исключение из источника данных исключает исключение из списка данных Spring и позволяет ему обрабатывать служебный/бизнес-уровень. Вы отправляете меньше информации, поймав и повторно бросив таким образом. – duffymo

+1

Hummm ... Я действительно так не думаю. Этот код уже находится в моем бизнесе/сервисе. Мой клиентский слой (html/javascript) должен знать только, что «ограничение первичного ключа» было нарушено. Зачем отправлять всю структуру исключений, если она не нужна? – outlookrperson

ответ

5

Где бы вы ни обрабатывать исключения, у вас есть возможность смотреть в getMostSpecificCause() или getRootCause() методов UnexpectedRollbackException. Here is information об этих методах.

+0

Хорошо. getMostSpecificCause() - это то, что я искал. Кажется, это решает мою проблему. Благодарю. – outlookrperson

+0

Рад помочь. Удачи с вашим проектом! – Vidya

3

Как и с другими, которые прокомментировали ваш вопрос - я тоже думаю, что решение, которое у вас есть на вашем посту, плохое. Единственная цель абстракции репозитория - скрыть механизм сохранения, чтобы клиенты не знали об этом. В вашем случае вы ищете низкоуровневое SQL Exception, которое было намеренно абстрагировано от Spring, а также JPA.

Если вы действительно хотите обработать нарушение ограничения, то DataIntegrityViolationException является правильным, чтобы поймать. Хранилища будут обертывать специфические хранилища (MongoDB, JPA, независимо от того, что вы используете) весной DataAccessException подтипов, чтобы клиенты могли делать именно это: улавливайте исключение для каждого типа ошибки, а не за механизм персистентности.

+0

Спасибо, Гьерке. Я вижу вашу мысль. Я пробовал это, но в моем случае метод insert() на уровне сервиса всегда будет зачислен в транзакцию (Propagation.REQUIRES_NEW). Таким образом, сгенерированное исключение будет UnexpectedRollbackException, являющимся подтипом TransactionException. DataAccessException находится в другой иерархии классов. Исключение catch для DataIntegrityViolationException никогда не будет обработано. – outlookrperson

+0

Интересно ... Рассматривая код управления транзакциями весной, единственная возможность, может возникнуть «UnexpectedRollbackException» * и *, несет в себе инфраструктуру JTA, которая бросает ее, а не репозиторий. Итак, в чем причина того, что вы должны использовать транзакции JTA в первую очередь? –

+0

Мне нужна операция (вставка/обновление), зарегистрированная в транзакции, потому что она включает модификацию в других объектах. Таким образом, на уровне сервиса метод украшен атрибутом @Transactional (распространение = Propagation.REQUIRES_NEW). Когда репозиторий называется его операциями, внутри транзакции. – outlookrperson