Подтвердить что ты не робот

Зачем нужны отдельные объекты в JPA?

Всегда есть так много вопросов, связанных с проблемами с отдельными объектами!

Во-первых, они часто вызывают LazyInitializationException в Hibernate. Да, есть еще один провайдер персистентности, который не бросает исключений,  но я думаю, что у них есть некоторые проблемы с последовательностью. Рассмотрим, что мы имеем A и B сущности, (@ManyToOne) от A до B, который должен быть непустым.

Мы начали нашу сессию, загрузили экземпляр A и затем закрыли сессию. После этого мы попытаемся получить ссылку на B. И предположим, что другая транзакция просто удалила как наши A, так и B экземпляры. Поэтому, когда мы запрашиваем из базы данных, мы не можем найти подходящий экземпляр B и получить null!

Таким образом, наш контракт нарушен. Некоторый код, который полагается на то, что a.getB() возвращает объект, который выдает NullPointerException. С постоянными сущностями это невозможно, потому что у нас есть все ленивые загрузка в той же транзакции с получением самого объекта, поэтому все операции являются атомарными (если у нас есть правильная изоляция транзакций, конечно).

Также есть проблемы, когда вы хотите хранить постоянные и отдельные объекты в одном Set. В этом случае вы всегда должны переопределять equals и hashCode, что обычно выглядит неудобно, поскольку я не вижу действительно хорошего способа сделать это.

Чтобы вернуть удаленный объект обратно в EntityManager, вы должны использовать merge, который является глючным.

Итак, мой вопрос: существует ли разумный сценарий, в котором действительно нужны отдельные объекты? Кроме того, когда вам приходится смешивать отдельные и постоянные объекты и объединить отдельные объекты в новый EntityManager?

4b9b3361

Ответ 1

Я объясню, почему этот сценарий не должен происходить и почему нам нужны отдельные объекты.

Считайте, что вы находитесь в транзакции JTA (JPA требует поддержки для нее) и извлекает a. Теперь вы можете вызывать a.getB() либо (1) в этой транзакции (т.е. Объект a управляется), либо (2) при отсоединении a.

Сценарий 1: теперь, в зависимости от уровня изоляции транзакций, вы можете увидеть или не увидеть, что делают другие транзакции. Например, если у вас есть уровень изоляции SERIALIZABLE, вы успешно получите a.getB(), даже если эта строка была удалена в параллельной транзакции. Если эта строка уже была удалена, и ваша транзакция увидела это, это означает, что ваша БД непоследовательна (нет внешнего ключа) или что вы использовали неправильный уровень изоляции транзакции.

Сценарий 2: объект a отсоединен. Когда выбрано LazyInitializationException, это означает, что вы слишком поздно вызвали a.getB(), чтобы гарантировать консистенцию в вашем приложении (поскольку a больше не управляется). Чтобы решить проблему, вы просто вызываете ее раньше, когда объект все еще управляется. NPE не может произойти.

Почему нам нужно ОТДЕЛЬНОЕ СОСТОЯНИЕ? Ну, нам нужно состояние, в котором изменения в экземпляре объекта не отслеживаются. Зачем?

Пример 1. Предположим, вы получили сущность (с постоянным идентификатором) на уровне EJB и что не было отсоединенного состояния (что означает, что все сущности должны управляться). Но нам нужно сделать валидацию, прежде чем продолжать сущность. Если этот объект будет автоматически управляться, его изменения будут автоматически сохраняться в БД. Итак, это новое состояние было введено.

Пример 2: вы получаете на уровне EJB объект, который вам нужно обновить ТОЛЬКО 5 полей из 10 из этого объекта. Если этот объект автоматически попадет в управляемое состояние, все 10 полей будут сохранены. Решение в этом случае состоит в том, чтобы получить управляемый объект и обновить 5 полей ТОЛЬКО в этом объекте.

Ответ 2

Отдельно - отдельный объект - это объект, который был постоянным, но его сеанс закрыт. Ссылка на объект все еще действителен, конечно, и отдельный экземпляр может даже в этом состоянии. Отдельный экземпляр может быть присоединен к новой сессии в более поздний момент времени, делая это (и все изменения). Эта функция позволяет программировать модель для длительных периодов работы, требующих времени мышления пользователя. Мы называть их транзакциями приложений, т.е. единицей работы из точки зрения пользователя.

Ссылки Hibernate DOc

Почему?

Сессия кэширует каждый объект, находящийся в постоянном состоянии (наблюдаемый и проверил на грязное состояние спящим). Если вы держите его открытым для долгое время или просто загружать слишком много данных, он будет расти бесконечно, пока вы получаете исключение OutOfMemoryException. Одним из решений является вызов clear() и evict(), чтобы управлять кешем сеанса, сохраняя сеанс открытым для продолжительность сеанса пользователя также означает более высокую вероятность устаревания данных.

Ссылки Снова Hibernate Doc

Готов поспорить, что вы не читали саму документацию в спящем режиме, у нее есть сценарии, объясняющие их тоже:)

Простое объяснение: применительно к постоянным объектам.

Предположим, что пользователь должен обновить форму, вы получите информацию о пользователе в из UserObject, Этот пользовательский объект является постоянным с сеансом. Теперь, если пользователь не отправляет форму, ваш сеанс открыт до тех пор, пока сервер сессия истекает, как долго вы будете ждать? Если вы использовали getCurrentSession, другой запрос формы приходит, когда предыдущий не представлены, теперь у вас есть грязные данные! Что делать, если ваш объект ожидая данных, которые должны появиться для веб-сервиса, и он принимает достаточно долго, вы все равно сохраните сеанс открытым, объект будет постоянным с сессия?

Ответ 3

Отдельные сущности существуют только для минимизации времени блокировки данных из-за транзакции, максимизируя количество одновременных пользователей. Конечно, это связано со стоимостью, и вы их перечислили. но поскольку слияние конфликтов обычно редко, люди принимают некоторые редкие ошибки.

Понимаете, хранилища данных всегда будут существовать, но они происходят меньше, когда транзакция короткая: -)

Ответ 4

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

Я не могу представить себе другие ситуации, и мне интересно узнать другие ответы.

Ответ 5

Отдельные объекты (нетерпеливые) могут работать как DTO в некоторых случаях. Вероятно, это не то, что должно быть сделано в корпоративном приложении, но, например, сетевая игра, основанная на java se, где и сервер, и клиент поступают из одной и той же кодовой базы, состояние игрока может быть перепечатано как сущность и перенесено на/с сервера и сохраняется там.

Не уверен, что это будет лучший выбор, чем правильный DTO, но это может быть технически сделано.

Ответ 6

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

проверьте это и прочитайте 3.3 слияние