Открыть сессию в виде шаблона
Я задаю этот вопрос с учетом выбранных мной сред разработки JPA (реализация Hibernate), Spring и <вставьте сюда инфраструктуру MVC - Struts 1, Struts 2, Spring MVC, Stripes...>.
Я немного подумал об отношениях на моем уровне сущности - например, у меня есть сущность заказа, которая имеет много строк заказа. Я настроил свое приложение так, чтобы оно охотно загружало строки заказов для каждого заказа. Считаете ли вы, что это ленивый способ обойти ленивые проблемы инициализации, с которыми я столкнусь, если установить для стратегии выборки значение false?
На мой взгляд, у меня есть следующие альтернативы при извлечении сущностей и их ассоциаций:
Используйте шаблон Open Session In View, чтобы создать сеанс для каждого запроса и зафиксировать транзакцию перед возвратом ответа.
Реализуйте слой DTO (Data Transfer Object) так, чтобы каждый выполняемый мной запрос DAO возвращал правильно инициализированный DTO для моих целей. Мне не очень нравится этот вариант, потому что по своему опыту я обнаружил, что он создает много шаблонного кода для копирования и становится грязным в обслуживании.
Не отображайте никакие ассоциации в JPA, чтобы каждый выполняемый запрос возвращал только те сущности, которые меня интересуют - это, вероятно, потребует от меня наличия DTO в любом случае, и будет неудобно поддерживать, и я думаю, что это побеждает цель иметь ORM на первом месте.
С нетерпением извлекайте все (или большинство ассоциаций) - в приведенном выше примере всегда извлекайте все строки заказа, когда я получаю заказ.
Поэтому мой вопрос: когда и при каких обстоятельствах вы бы использовали какой из этих вариантов? Вы всегда придерживаетесь одного способа сделать это?
Я бы попросил коллегу, но думаю, что если бы я даже упомянул термин "Открытая сессия в поле зрения", меня бы встретили пустыми взглядами:(Что я действительно ищу, так это несколько советов от старшего или очень опытного разработчика.
Спасибо, парни!
6 ответов
Я успешно решил все свои ленивые проблемы инициализации с помощью Open Session In View -pattern (т.е. реализация Spring). Технологии, которые я использовал, были такими же, как и у вас.
Использование этого шаблона позволяет мне полностью отобразить отношения сущностей и не беспокоиться о получении дочерних сущностей в дао. В основном. В 90% случаев шаблон решает ленивые потребности инициализации в представлении. В некоторых случаях вам придется "вручную" инициализировать отношения. Эти случаи были редкими и всегда включали очень очень сложные отображения в моем случае.
При использовании шаблона Open Entity Manager In View важно правильно определить отношения сущностей и особенно параметры распространения и транзакций. Если они не настроены должным образом, будут возникать ошибки, связанные с закрытыми сеансами, когда какой-либо объект лениво инициализируется в представлении и происходит сбой из-за того, что сеанс уже закрыт.
Я определенно выбрал бы вариант 1. Вариант 2 иногда может быть необходим, но я не вижу абсолютно никакой причины использовать вариант 3. Вариант 4 также является "нет нет". Стремительная загрузка всего убивает производительность любого представления, которому нужно перечислить только несколько свойств некоторых родительских объектов (в данном случае это порядки).
N+1 выбирает
Во время разработки будет выбрано N+1 в результате инициализации некоторых отношений в представлении. Но это не повод отказаться от паттерна. Просто исправьте эти проблемы по мере их возникновения и перед доставкой кода в производство. Исправить эти проблемы с помощью шаблона OEMIV так же легко, как и с любым другим шаблоном: добавить надлежащие методы dao или service, настроить контроллер на вызов другого метода поиска, возможно, добавить представление в базу данных и т. Д.
У Open Session in View есть некоторые проблемы.
Например, если транзакция завершится неудачно, вы можете знать об этом слишком поздно во время фиксации, как только вы почти закончили рендеринг своей страницы (возможно, ответ уже зафиксирован, поэтому вы не можете изменить страницу!) ... Если бы вы знали эта ошибка раньше, вы следовали бы за другим потоком и закончили бы рендерингом другой страницы...
Другой пример: чтение данных по требованию может обернуться многими проблемами "выбор N+1", которые снижают производительность.
Многие проекты используют следующий путь:
- Поддерживать транзакции на бизнес-уровне; загрузите в этот момент все, что вам нужно.
- Уровень представления подвержен риску LazyExceptions: каждый считается ошибкой программирования, обнаруживается во время тестов и исправляется путем загрузки большего количества данных в бизнес-уровень (у вас есть возможность сделать это эффективно, избегая проблем "выбор N+1").
Чтобы избежать создания дополнительных классов для DTO, вы можете загрузить данные внутри самих объектов. В этом весь смысл подхода POJO (используется современными уровнями доступа к данным и даже технологиями интеграции, такими как Spring).
Я успешно использовал шаблон Open-Session-in-View в проекте. Однако недавно я прочитал в "Spring In Practice" интересную потенциальную проблему с неповторяющимися операциями чтения, если вы управляете своими транзакциями на более низком уровне, сохраняя сеанс Hibernate открытым на уровне представления.
Мы управляли большинством наших транзакций на уровне сервисов, но оставляли сеанс гибернации открытым на уровне просмотра. Это означало, что отложенное чтение в представлении приводило к отдельным транзакциям чтения.
Мы управляли нашими транзакциями на нашем уровне обслуживания, чтобы минимизировать продолжительность транзакции. Например, некоторые из наших вызовов службы привели как к транзакции базы данных, так и к вызову веб-службы для внешней службы. Мы не хотели, чтобы наша транзакция была открыта во время ожидания ответа на запрос веб-службы.
Поскольку наша система никогда не была запущена в производство, я не уверен, были ли с ней какие-либо реальные проблемы, но я подозреваю, что у представления была возможность попытаться лениво загрузить объект, который был удален кем-то другим.
Есть некоторые преимущества подхода DTO. Вы должны заранее подумать, какая информация вам нужна. В некоторых случаях это не даст вам сгенерировать n+1 оператор выбора. Это также помогает увидеть, где использовать активные выборки и / или оптимизированные представления.
Я также перенесу свой вес на модель Open-Session-in-View, будучи в той же лодке и раньше.
Я работаю с Stripes без пружины и создал ручной фильтр, прежде чем он будет работать хорошо. Как вы уже упоминали, кодирование логики транзакций на бэкэнде становится очень быстрым. Страстная загрузка всего становится УЖАСНЫМ, когда вы сопоставляете все больше и больше объектов друг с другом.
Хочу добавить, что вы, возможно, не сталкивались с такими вещами, как Stripersist и Stripernate - Stripersist - более вкусный JPA - фильтры для автоматической гидратации, которые снимают большую часть работы с ваших плеч.
С Stripersist вы можете говорить такие вещи, как /appContextRoot/actions/view/3
и он будет автоматически гидратировать сущность JPA в ActionBean с идентификатором 3, прежде чем будет выполнено событие.
Stripersist находится в пакете с нашивками на sourceforge. Теперь я использую это для всех новых проектов, так как он чистый и легко поддерживает несколько источников данных, если это необходимо.
Составляют ли строки заказа и заказа большой объем данных? Участвуют ли они в онлайн-процессах, где требуется ответ в режиме реального времени? Если это так, вы можете подумать, не использовать ли усердную выборку - это сильно влияет на производительность. Если объем данных невелик, проблем с загрузкой нет.
Что касается использования DTO, это может быть жизнеспособной реализацией. Если ваш бизнес-уровень используется внутренне вашим собственным приложением (т. Е. Небольшим веб-приложением и его бизнес-логикой), вероятно, было бы лучше использовать ваши собственные сущности в вашем представлении с шаблоном открытого сеанса в представлении, поскольку это проще.
Если ваши сущности используются многими приложениями (например, внутренним приложением, предоставляющим услугу в вашей корпорации), было бы интересно использовать DTO, так как вы не представляли бы свою модель своим клиентам. Раскрытие этого может означать, что вам будет сложнее рефакторинг вашей модели, поскольку это может означать разрыв контрактов с вашими клиентами. DTO сделает это проще, так как у вас есть еще один уровень абстракции. Это может быть немного странно, поскольку EJB3 теоретически устраняет необходимость в DTO.