Почему нам нужно использовать граф сущностей?
Я склонялся JPA
и я обнаружил, что мы можем использовать граф сущности, так как JPA
2.1.
Но я еще не понял достоинства графа сущностей.
Я знаю, что одним из достоинств использования графа сущностей является то, что мы можем указывать только те данные, которые мы хотим получить среди всей сущности, но в случае, если мы хотим целую сущность, есть ли какая-либо другая причина использовать граф сущностей? или мы должны использовать граф сущностей только тогда, когда мы хотим получить частичные данные?
если есть другой смысл или цель, когда мы используем граф сущностей, я хотел бы знать это.
2 ответа
JPA Entity Graph
позволяет переопределить план выборки по умолчанию.
План выборки по умолчанию
Как я объяснил в этой статье , каждая сущность имеет план выборки по умолчанию, который определяется во время сопоставления сущностей и указывает Hibernate, как извлекать ассоциации сущностей.
По умолчанию и ассоциации используют стратегию FetchTyp.EAGER, что является ужасным выбором с точки зрения производительности. По этой причине рекомендуется устанавливать все
@ManyToOne
и
@OneToOne
ассоциации использовать
FetchType.LAZY
стратегия, как в следующем примере:
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
//Getters and setters omitted for brevity
}
При получении объекта с помощью метода:
PostComment comment = entityManager.find(PostComment.class, 1L);
Hibernate выполняет следующий SQL-запрос:
SELECT pc.id AS id1_1_0_,
pc.post_id AS post_id3_1_0_,
pc.review AS review2_1_0_
FROM post_comment pc
WHERE pc.id = 1
Связь выбирается как прокси , у которого есть только
id
установлен
post_id
Столбец внешнего ключа, загруженный вышеупомянутым SQL-запросом.
При доступе к любому свойству прокси, не являющемуся идентификатором:
LOGGER.info("The comment post title is '{}'", comment.getPost().getTitle());
Выполняется вторичный SQL-запрос, извлекающий
Post
организация по запросу:
SELECT p.id AS id1_0_0_,
p.title AS title2_0_0_
FROM post p
WHERE p.id = 1
-- The comment post title is 'High-Performance Java Persistence, part 1'
Отмена плана выборки по умолчанию
Если мы хотим переопределить план выборки по умолчанию и быстро получить ассоциацию во время выполнения запроса, мы можем использовать запрос JPQL, который инструктирует Hibernate получить ленивую ассоциацию с помощью предложения FETCH JOIN:
PostComment comment = entityManager.createQuery("""
select pc
from PostComment pc
left join fetch pc.post
where pc.id = :id
""", PostComment.class)
.setParameter("id", 1L)
.getSingleResult();
LOGGER.info("The comment post title is '{}'", comment.getPost().getTitle());
Затем план выборки по умолчанию будет переопределен, и ассоциация будет загружена с нетерпением:
SELECT pc.id AS id1_1_0_,
p.id AS id1_0_1_,
pc.post_id AS post_id3_1_0_,
pc.review AS review2_1_0_,
p.title AS title2_0_1_
FROM post_comment pc
LEFT JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1
Декларативный график сущностей JPA
План выборки по умолчанию также можно переопределить с помощью графа сущностей JPA. Например, мы могли бы определить конкретный план выборки, используя следующую аннотацию JPA:
@Entity(name = "PostComment")
@Table(name = "post_comment")
@NamedEntityGraph(
name = "PostComment.post",
attributeNodes = @NamedAttributeNode("post")
)
public class PostComment {
//Code omitted for brevity
}
С
PostComment.post
EntityGraph готов, теперь мы можем загрузить
PostComment
сущность вместе с связанной с ней
post
сущность, например:
PostComment comment = entityManager.find(
PostComment.class,
1L,
Collections.singletonMap(
"javax.persistence.loadgraph",
entityManager.getEntityGraph("PostComment.post")
)
);
И при выполнении вышеуказанного
find
, Hibernate генерирует следующий запрос SQL SELECT:
SELECT pc.id AS id1_1_0_,
pc.post_id AS post_id3_1_0_,
pc.review AS review2_1_0_,
p.id AS id1_0_1_,
p.title AS title2_0_1_
FROM post_comment pc
LEFT OUTER JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1
Если вы используете Spring, вы можете ссылаться на JPA EntityGraph в методе репозитория, используя
@EntityGraph
аннотация:
@Repository
public interface PostCommentRepository
extends CrudRepository<PostComment, Long> {
@EntityGraph(
value = "PostComment.post",
type = EntityGraphType.LOAD
)
PostComment findById(Long id);
}
Программный график сущностей JPA
Если вам не нравятся аннотации, вы также можете программно построить JPA EntityGraph, используя
createEntityGraph
метод JPA
EntityManager
, как показано в следующем примере:
EntityGraph<PostComment> postCommentGraph = entityManager
.createEntityGraph(PostComment.class);
postCommentGraph.addAttributeNodes("post");
PostComment comment = entityManager.find(
PostComment.class,
1L,
Collections.singletonMap(
"javax.persistence.loadgraph",
postCommentGraph
)
);
- В Jpa hibernate выборка сущностей с ассоциациями всегда была вопросом производительности.
- Ленивая загрузка ассоциаций в транзакцию снова и снова приводит к проблемам выбора n+1, и для избежания таких проблем используются JPQL join fetch и Cr iteria api объединения. Но выборка данных с этими двумя также приводит к проблемам перекрестного соединения, что означает, что перекрестное объединение всех записей таблицы возвращается в состояние гибернации.
- Кроме того, изменение переменной выборки, определенной в аннотациях на уровне объекта, также не является хорошим вариантом для варианта использования.
- Следовательно, для решения вышеупомянутых двух проблем были введены графы сущностей. Все узлы, определенные в графе сущностей, всегда извлекаются с нетерпением, независимо от их определения на уровне сущности. Эти графики передаются как подсказка для запросов.
- Передавая графы в качестве подсказки, решаются проблемы перекрестного объединения, а также можно изменить поведение аннотации, заданное уровнем извлечения ассоциации.
Для кода вы можете проверить мой репозиторий GitHub: