Я обычно использую Hibernate в сочетании со средой Spring и его возможностями декларативного разграничения транзакций (например, @Transactional ).
Как все мы знаем, спящий режим старается быть максимально неинвазивным и прозрачным , однако это оказывается немного сложнее при использовании lazy-loaded
отношений.
Я вижу несколько вариантов дизайна с разным уровнем прозрачности.
- Сделайте отношения не перегруженными ленивыми отношениями (например,
fetchType=FetchType.EAGER)
- Это нарушает всю идею отложенной загрузки.
- Инициализировать коллекции с помощью
Hibernate.initialize(proxyObj);
- Это подразумевает относительно высокую степень связи с DAO.
- Хотя мы можем определить интерфейс с помощью
initialize
, другие реализации не гарантируют предоставления каких-либо эквивалентов.
- Добавьте поведение транзакции к
Model
самим постоянным объектам (используя либо динамический прокси, либо@Transactional
)- Я не пробовал использовать динамический прокси-сервер, хотя мне никогда не удавалось заставить @Transactional работать с самими постоянными объектами. Вероятно, из-за этого спящий режим - это работа с прокси-сервером.
- Потеря контроля над фактическими транзакциями
- Предоставьте как ленивый, так и неленивый API, например,
loadData()
иloadDataWithDeps()
- Заставляет приложение знать, когда какую процедуру использовать, опять же жесткая связь
- Переполнение метода,,
loadDataWithA()
....,loadDataWithX()
- Принудительный поиск зависимостей, например, путем предоставления только
byId()
операций- Требуется много не объектно-ориентированных подпрограмм, например,,
findZzzById(zid)
а затемgetYyyIds(zid)
вместоz.getY()
- Может быть полезно получать каждый объект в коллекции по одному, если между транзакциями возникают большие накладные расходы на обработку.
- Требуется много не объектно-ориентированных подпрограмм, например,,
- Сделайте частью приложения @Transactional, а не только DAO
- Возможные аспекты вложенных транзакций
- Требуются процедуры, адаптированные для управления транзакциями (например, достаточно маленькие)
- Небольшое влияние на программу, хотя может привести к крупным транзакциям.
- Предоставьте DAO динамические профили выборки , например,
loadData(id, fetchProfile);
- Приложения должны знать, какой профиль использовать, когда
- Тип транзакций AoP, например, операции перехвата и выполнение транзакций при необходимости
- Требуется манипулирование байтовым кодом или использование прокси
- Потеря контроля при совершении транзакций
- Черная магия, как всегда :)
Я пропустил какой-нибудь вариант?
Какой подход вы предпочитаете, пытаясь свести к минимуму влияние lazy-loaded
взаимосвязей в дизайне приложения?
(Ой, извините за WoT )
java
hibernate
spring
lazy-loading
application-design
Йохан Сьёберг
источник
источник
Ответы:
Я бы сказал, что первоначальное предположение неверно. Прозрачная персистентность - это миф, поскольку приложение всегда должно заботиться о жизненном цикле сущности и размере загружаемого графа объекта.
Обратите внимание, что Hibernate не может читать мысли, поэтому, если вы знаете, что вам нужен определенный набор зависимостей для конкретной операции, вам нужно как-то выразить свои намерения в Hibernate.
С этой точки зрения решения, которые явно выражают эти намерения (а именно, 2, 4 и 7), выглядят разумными и не страдают отсутствием прозрачности.
источник
Я не уверен, на какую проблему (из-за лени) вы намекаете, но для меня самая большая проблема - избежать потери контекста сеанса в моих собственных кешах приложений. Типичный случай:
foo
загружается и помещается на карту;foo.getBar()
(что-то, что никогда раньше не вызывалось и вычисляется лениво);Итак, чтобы решить эту проблему, у нас есть ряд правил:
OpenSessionInViewFilter
переносить сеансы (например, для веб-приложений);try/finally
), поэтому подклассам не нужно думать об этом;Как видите, это действительно далеко от неинвазивного и прозрачного . Но цена по-прежнему терпима по сравнению с ценой, которую мне пришлось бы заплатить за нетерпеливую загрузку. Проблема с последним состоит в том, что иногда это приводит к эффекту бабочки при загрузке одного объекта, на который имеется ссылка, не говоря уже о коллекции сущностей. Потребление памяти, загрузка процессора и задержка, если не упомянуть, также намного хуже, так что я думаю, что смогу с этим жить.
источник
transparency
заключается в том, что приложение заставляет заботиться о загрузке ленивых объектов. Если бы все было извлечено с нетерпением, приложение могло бы не знать, сохраняются ли объекты в базе данных или нет, посколькуFoo.getBar()
всегда будет успешным. >when passing objects between threads, pass IDs
Да, это соответствовало бы №5.Очень распространенный шаблон - использовать OpenEntityManagerInViewFilter, если вы создаете веб-приложение.
Если вы создаете службу, я бы открыл TX в общедоступном методе службы, а не в DAO, поскольку очень часто метод требует получения или обновления нескольких сущностей.
Это устранит любое «исключение отложенной загрузки». Если вам нужно что-то более продвинутое для настройки производительности, я думаю, что профили выборки - это то, что вам нужно.
источник
OSIV
прежнему является антипаттерном и приводит к очень серьезным проблемам, таким как неспособность корректно обрабатывать исключения или снижение производительности. Подводя итог: IMHO OSIV - простое решение, но годное только для игрушечных проектов.