Рассмотрим следующие две таблицы - сообщения и комментарии схемы базы данных блога, где таблица сообщений имеет отношение «один ко многим» с таблицей комментариев.
Я использую Двунаправленное отображение "один ко многим", потому что только мои дочерние объекты ограничены.
В Двунаправленное отображение "один ко многим" я написал один вызов отдыха, чтобы получить всю публикацию с соответствующими комментариями для публикации. Используя метод поиска всех по умолчанию в репозитории JPA.
Но произошло следующее исключение:
"message": "Could not write JSON: failed to lazily initialize a collection of role: com.insights.apartmento.modal.Post.comments, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.insights.apartmento.modal.Post.comments, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.insights.apartmento.modal.Post[\"comments\"])",
Мой класс Pojo следующим образом
In POST POJO
@Entity
@Table(name = "posts")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Size(max = 100)
@Column(unique = true)
private String title;
@Size(max = 250)
private String description;
@Lob
private String content;
@OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "post")
private Set<Comment> comments = new HashSet<>();
// Getters and Setters (Omitted for brevity)
}
In Comments POJO
@Entity
@Table(name = "comments")
public class Comment{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Lob
private String text;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
private Post post;
// Getters and Setters (Omitted for brevity)
}
В сопоставлении «один ко многим» определите тип выборки как EAGER.
@OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
mappedBy = "post")
Вы пытаетесь сериализовать объект Post напрямую. Происходит то, что Jackson marshaller пытается построить JSON из полного класса, включая private Set<Comment> comments.
Поскольку вы используете Lazy FetchType (правильно, по моему мнению), Hibernate выдаст LazyInitializationException
Избежать этого можно несколькими способами:
comments в сгенерированном JSON, используя аннотацию @JsonIgnore для этого свойства.FetchType (например, EAGER или JOIN)Hibernate.initializeКакое решение использовать? Это зависит от вашего варианта использования. В любом случае я настоятельно рекомендую вам избегать решения номер 2 (полностью загрузить объект Post, но с использованием другого FetchType (например, EAGER или JOIN), потому что это означает, что вы всегда будете загружать сообщения со всеми комментариями, и это очень влияет на производительность
Ваша ассоциация @OneToMany выбирается лениво, что всегда должно быть вашим предпочтительный FetchType. Он работает намного лучше, чем выборка EAGER.
Но тогда вам нужно убедиться, что вы инициализировали все необходимые ассоциации, прежде чем закрывать Session или отправлять объект сущности любому клиенту. В вашем случае маршалинг JSON происходит после закрытия сеанса, что вызвало исключение.
Есть несколько способов инициализировать ленивую ассоциацию. Самый простой - это предложение JOIN FETCH в запросе JPQL, например:
SELECT p FROM Post p LEFT JOIN FETCH p.comments c WHERE p.id = :id
Если вы используете em.find для загрузки объекта Post, вам нужно либо заменить его на Запрос JPQL или используйте EntityGraph.
Скорее всего, вы не работаете с определенной границей транзакции. При отложенной загрузке вам необходимо определить как минимум транзакцию только для чтения, если вы хотите пройти по графу и таким образом получить дочерние записи. Подсказка здесь - «нет сеанса». Оберните вызов класса обслуживания в @Transactional, и все будет хорошо. Определите доступ только для чтения, если вам не нужно делать никаких обновлений.
Пожалуйста, не используйте
FetchType.EAGER. Он заставляет Hibernate всегда получать связанные объекты, даже если они вам не нужны. Это один из наиболее распространенные ошибки производительности с JPA и Hibernate.