Сущность JPA Spring Data для использования вне транзакции - PullRequest
0 голосов
/ 25 декабря 2018

У меня есть приложение Spring Boot со службой, которая возвращает сущность Spring Data, доступную контроллеру.Проблема в том, что я знаю, что не стоит использовать сущности вне транзакций с БД, так что бы вы рекомендовали:

Рассмотрим следующую службу:

@Transactional
public MyData getMyData(Long id) {
    return myDataRepository.findById(id);
}

где MyDataбаза данных @Entity и myDataRepository является JpaRepository

Этот метод службы вызывается из класса контроллера, который отправляет этот объект в формате JSON клиенту, который вызывает этот метод.

@RequestMapping("/")
public ResponseEntity<?> getMyData(@RequestParam Long id) {
    return myService.getMyData(id);
}

Если я выставлю MyData контроллеру, то он будет открыт вне транзакции и может вызвать всевозможные ошибки гибернации.Каковы лучшие практики для этих сценариев?Должен ли я преобразовать сущность в POJO в сервисе и вернуть MyDataPOJO вместо MyData в MyService?

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

Использование сущностей вне транзакций не обязательно приводит к проблемам;у него могут быть действительные варианты использования.Тем не менее, есть довольно много переменных в игре, и как только вы выпустите их из поля зрения, вещи могут и пойдут на юг.Рассмотрим следующие сценарии:

  1. Ваша сущность не имеет никаких связей с другими сущностями, или эти связи довольно поверхностные и охотно извлекаются.Вы извлекаете эту сущность из хранилища, отсоединяете ее от модуля сохранения (неявно или явно) и передаете контроллеру.Контроллер не пытается изменить объект;он только сериализует его в JSON - полностью безопасно.
  2. То же, что и выше, но контроллер изменяет сущность перед сериализацией его в JSON - опять же, полностью безопасно (только не ожидайте, что эти изменения будут отражены в БД)
  3. То же, что и выше, но вы забыли отсоединить сущность от PU - ой, если контроллер изменяет сущность, вы можете либо увидеть ее отражение в БД, либо получить исключение закрытой транзакции;оба, скорее всего, непредвиденные последствия.
  4. То же, что и выше, но некоторые отношения сущности ленивы.Опять же, вы можете или не можете получить какие-либо исключения в зависимости от того, обращаются ли к этим ленивым свойствам или нет.
  5. И есть еще очень много комбинаций преднамеренного и непреднамеренного выбора дизайна ...

Как видите, вещи могут очень быстро выйти из-под контроля.Особенно, когда ваша модель должна развиваться: вскоре вы обнаружите, что возитесь с представлениями JSON, @JsonIgnore, проекциями сущностей и так далее.Таким образом, эмпирическое правило: хотя может показаться заманчивым срезать некоторые углы и подвергать ваши объекты внешним слоям, это редко хорошая идея.Правильно спроектированное решение всегда имеет четкое разделение проблем между уровнями:

  • Уровень персистентности никогда не предоставляет больше методов или объектов, чем требуется бизнес-логикой.Более того, одну и ту же таблицу (таблицы) можно и нужно отображать в несколько различных объектов в зависимости от случаев использования, в которых они участвуют.
  • Уровень бизнес-логики (кстати, это ваш API, а не службы REST! ​​См. Ниже)) никогда не вытекает какие-либо детали из персистентного слоя.Его методы четко определяют варианты использования из проблемной области.
  • Уровень представления только переводит API, предоставленный бизнес-логикой, в ту или иную форму, подходящую для клиента, и никогда не реализует дополнительные варианты использования.Имейте в виду, что контроллеры REST, службы SOAP и т. Д. Логически являются частью уровня представления, а не бизнес-логики.

Так что да, краткий ответ таков: персистентные сущности не должны подвергаться воздействию внешних слоев.Одним из распространенных методов является использование DTO вместо этого;кроме того, объекты DTO предоставляют дополнительный уровень абстракции на случай, если вам нужно изменить свои сущности, но оставить API нетронутым или наоборот.Если в какой-то момент ваши DTO очень похожи на ваши сущности, существуют платформы отображения bean-компонентов Java, такие как Dozer, Orika, MapStruct, JMapper, ModelMapper и т. Д., Которые помогают устранить шаблонный код.

Попробуйте поискать «шестиугольную архитектуру»,Это очень интересная концепция для создания четко разделенных слоев.Вот одна из статей на эту тему https://blog.octo.com/en/hexagonal-architecture-three-principles-and-an-implementation-example/;, в которой используются примеры на C #, но они довольно просты.

0 голосов
/ 25 декабря 2018

Вы никогда не должны передавать внутреннюю модель внешним ресурсам (в вашем случае - @RestController).Упомянутый вами «POJO» обычно называется DTO (объект передачи данных).DTO может быть определен как интерфейс на стороне службы и реализован на стороне контроллера.Служба затем, как вы описали, преобразует внутреннюю модель в экземпляр DTO, обеспечивая более слабую связь между контроллером и службой.

Определяя интерфейс DTO на стороне службы, вы получаетедополнительное преимущество в том, что вы можете оптимизировать свои постоянные доступы, только выбирая данные, указанные в соответствующем DTO-интерфейсе.Например, нет необходимости извлекать friends из User, если @Controller специально не запрашивает их, поэтому вам не нужно выполнять дополнительные JOIN в базе данных (при условии, что вы используетебазы данных).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...