Hibernate lazy-load application design


я предпочитаю использовать Hibernate в сочетании с Весна рамки и это декларативные возможности демаркации транзакций (например, @Transactional).

как мы все знаем, hibernate пытается быть как неинвазивная и прозрачный как это возможно, однако это доказывает немного сложнее при использовании lazy-loaded отношения.


я вижу несколько вариантов дизайна с различными уровнями прозрачности.

  1. сделать отношения не лениво загружены (например,fetchType=FetchType.EAGER)
    • это виоалитес вся идея ленивой загрузки ..
  2. инициализировать коллекции с помощью Hibernate.initialize(proxyObj);
    • это подразумевает относительно высокую связь с DAO
    • хотя мы можем определить интерфейс с initialize, другие реализации не гарантируется предоставление какого-либо эквивалента.
  3. добавить поведение транзакции к постоянному Model сами объекты (с помощью динамический прокси или @Transactional)
    • я не пробовал подход динамического прокси, хотя мне никогда не казалось, что @Transactional работает над самими постоянными объектами. Вероятно, из-за того, что hibernate работает на прокси-сервере.
    • потеря контроля при совершении операций на самом деле происходит
  4. обеспечить как ленивый / не ленивый API, например,loadData() и loadDataWithDeps()
    • заставляет приложение знать, когда использовать какую процедуру, снова плотное соединение
    • переполнение способ, loadDataWithA(), ....,loadDataWithX()
  5. принудительный поиск зависимостей, например, только предоставляя byId() операции
    • требует много не объектно-ориентированных программ, например, findZzzById(zid), а потом getYyyIds(zid) вместо z.getY()
    • может быть полезно извлекать каждый объект в коллекции один за другим, если между транзакциями есть большие накладные расходы на обработку.
  6. принять участие приложение @ Transactional вместо только Дао
    • возможные соображения вложенных транзакций
    • требуются процедуры, адаптированные для управления транзакциями (например, достаточно малые)
    • небольшой программное воздействие, хотя и может привести к большим транзакциям
  7. обеспечить DAO с динамическим fetch profiles, например, loadData(id, fetchProfile);
    • приложения должны знать, какой профиль использовать, когда
  8. тип транзакций AoP, например, перехват операций и выполнение транзакций при необходимости
    • требуется манипуляция байт-кодом или использование прокси
    • потеря контроля при операциях выполняются
    • черная магия, как всегда :)

я пропустил какой-либо вариант?


который является вашим предпочтительным подходом при попытке свести к минимуму воздействие lazy-loaded отношения в ваше приложение?

(О, и извините за WoT)

3 84

3 ответа:

как мы все знаем, hibernate пытается быть максимально неинвазивным и прозрачным

Я бы сказал, что первоначальное предположение неверно. Transaparent persistence-это миф, так как приложение всегда должно заботиться о жизненном цикле объекта и размере загружаемого графа объекта.

обратите внимание, что Hibernate не может читать мысли, поэтому, если вы знаете, что вам нужен определенный набор зависимостей для конкретной операции, вам нужно выразить свои намерения как-то впасть в спячку.

Я не уверен, на какую проблему (вызванную ленивостью) вы намекаете, но для меня самая большая боль-это не потерять контекст сеанса в моих собственных кэшах приложений. Типичный случай:

  • объект foo загружается и помещается в карту;
  • другой поток берет этот объект с карты и вызывает foo.getBar() (то, что никогда не вызывалось раньше и лениво оценивается);
  • бум!

Итак, для решения этой проблемы у нас есть ряд правила:

  • оберните сеансы как можно прозрачнее (например,OpenSessionInViewFilter для webapps);
  • имеют общий API для потоков / пулов потоков, где привязка/развязка сеанса БД выполняется где-то высоко в иерархии (завернутый в try/finally) Так что подклассы не должны думать об этом;
  • при передаче объектов между потоками, передавать идентификаторы вместо самих объектов. Получая поток может загрузить объект, если это необходимо;
  • при кэшировании объектов никогда не кэшируйте объекты но их удостоверения личности. Имейте абстрактный метод в своем DAO или классе диспетчера, чтобы загрузить объект из кэша гибернации 2-го уровня, когда вы знаете идентификатор. Стоимость извлечения объектов из кэша гибернации 2-го уровня по-прежнему намного дешевле, чем переход в БД.

это, как вы можете видеть, это действительно близко к неинвазивный и прозрачный. Но стоимость все еще терпима, чтобы сравнить с ценой, которую я должен был бы заплатить за нетерпеливую загрузку. Проблема с последним заключается в том, что иногда это приводит к эффекту бабочки при загрузке одного ссылочного объекта, не говоря уже о коллекции объектов. Потребление памяти, использование процессора и латентность, чтобы упомянуть наименьшее, также намного хуже, поэтому я думаю, что могу жить с этим.

очень распространенным шаблоном является использование OpenEntityManagerInViewFilter Если вы создаете веб-приложения.

Если вы создаете службу, я бы открыл TX на общедоступном методе службы, а не на DAOs, так как очень часто метод требует получения или обновления нескольких объектов.

Это решит любое "ленивое исключение нагрузки". Если вам нужно что-то более продвинутое для настройки производительности, я думаю, что профили выборки-это путь.