Когда отношения ManyToOne с ленивой загрузкой JPA могут быть загружены вне транзакции?

У меня есть класс ресурсов JAX-RS. Он вызывает компонент EJB без сохранения состояния, который загружает объект (назовем его Parent).

Parent имеет связь @ManyToOne с другим объектом (назовем его Child) и настроен на тип выборки LAZY.

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

В отладчике я наблюдаю, что Parent, возвращаемое EJB, имеет null в качестве значения Child, как я и подозревал. Таким образом, ленивая загрузка работает нормально.

Затем мой класс ресурсов строит Response и передает управление внутренностям JAX-RS. Опять же, ни одна транзакция не открыта.

После сериализации отображаемый JSON (в моем случае) содержит все поля Child. Что-то во внутренностях JAX-RS каким-то образом «раздувает» эту ссылку Child вне транзакции.

Я наблюдаю в отладчике, что действительно в какой-то момент после того, как JAX-RS взял на себя управление, ссылка Child стала не-null.

Я думал, что либо Child должно было остаться null, либо должно было быть выброшено какое-то исключение, чтобы указать, что кто-то пытался получить доступ к лениво загруженному полю. Я явно что-то неправильно понял.

При каких обстоятельствах лениво загружаемые отношения отдельной сущности JPA могут быть «раздуты» вне транзакции?

Если это имеет значение, я использую Jersey 2.10.4 через Glassfish 4.1 и EclipseLink 2.5.2 (опять же, через Glassfish 4.1).


person Laird Nelson    schedule 24.01.2015    source источник
comment
Возможно, я вижу поведение, характерное для EclipseLink? Этот вопрос кажется актуальным .   -  person Laird Nelson    schedule 24.01.2015


Ответы (2)


если он действительно «отсоединен», то контекста нет, а значит, нет загрузки. Если он все еще в контексте, то, очевидно, он может загружать поля. Это согласно спецификации JPA.

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

person Neil Stockton    schedule 25.01.2015
comment
Насколько я понимаю, контекст персистентности в области транзакции (как обычно встречается в самых разнообразных приложениях на основе сеансовых компонентов без сохранения состояния) имеет срок службы, определяемый транзакцией. Если это так, то после завершения (транзакционного) метода EJB не существует контекста, в котором должна находиться сущность, и, следовательно, сущность действительно отсоединена. Тем не менее я вижу ленивую загрузку. Я совместим с JPA (без дескрипторов, опций и т. д. EclipseLink). Это меняет ваш ответ? Спасибо за ваше время. - person Laird Nelson; 25.01.2015
comment
Является ли контекст транзакцией или расширенным, просто определяет, КОГДА объекты отсоединены, и если объект ОТСОЕДИНЕН, то он не связан с контекстом... что означает ОТСОЕДИНЕНИЕ. Это ничего не меняет в моем ответе. Скорее всего, вы используете другую функцию интерпретации/расширения EclipseLink, как указано в objectdb.com/database. /forum/155 но, как я уже сказал, вы не можете полагаться на это и быть независимыми от поставщиков - person Neil Stockton; 26.01.2015
comment
Спасибо, Нил. Да, перефразируя (эквивалентно), после возврата моего EJB-метода любая возвращаемая им сущность должна быть по определению отсоединенной. Полностью согласен. Таким образом, я слышу, как вы говорите: если объект отсоединен, а это так и есть, то любая загрузка ленивых отношений, которую он может выполнять, нарушает спецификацию JPA. Правильный? - person Laird Nelson; 26.01.2015
comment
Да, именно так его интерпретирует большинство реализаций JPA. Однако, как говорится в этой ссылке, если EclipseLink имеет «отсоединенный» объект, в то время как EM может быть закрыт или недоступен, этот объект (каким-то образом) сохраняет ссылку на EMF, поэтому все еще может извлекать поля (следовательно, на самом деле не отсоединен в том же смысле, в каком его интерпретируют все другие реализации). - person Neil Stockton; 26.01.2015
comment
Спасибо. Да, что меня всегда беспокоило в этой функции поставщика, так это нетранзакционная природа загружаемого объекта. Возможно, я что-то упускаю, но если в момент исходной транзакции отложенный объект на диске имел состояние X, а затем после транзакции срабатывает отложенная загрузка, и объект на диске изменил состояние на Y... это кажется потенциально плохим. Еще раз спасибо. - person Laird Nelson; 26.01.2015

Нет необходимости начинать транзакцию, если вы только читаете объекты. Например, следующий код не требует транзакции:

ParentEntity pe = entityManager.find(ParentEntity.class,1);
List<ChildEntity> childs = pe.getChildList();
System.out.println(childs.size());

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

person ioko    schedule 26.01.2015