Рубрики
Без рубрики

Как работают методы поиска и getReference EntityManager при использовании JPA и гибернации

Узнайте разницу между методами поиска и getReference интерфейса EntityManager при использовании JPA и Hibernate.

Автор оригинала: Vlad Mihalcea.

Во время моего Высокопроизводительного обучения сохраняемости Java я понял , что не все разработчики знакомы с методом getReference JPA EntityManager и большинство из них используют find почти исключительно.

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

Смотрите разницу между методом поиска и getReference в JPA и #Hibernate@vlad_mihalcea https://t.co/vfnBexGpOt pic.twitter.com/xMqeh8Lf2f

В следующих примерах рассмотрим, что у нас есть родительская Запись сущность и дочерний Комментарий к сообщению , который имеет @ManyToOne связь со своим родителем:

Объект Post отображается следующим образом:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    private Long id;

    private String title;

    //Getters and setters omitted for brevity
}

И Комментарий к сообщению вот так:

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;

    //Getters and setters omitted for brevity
}

Причина, по которой ассоциация @ManyToOne использует Тип выборки.Атрибут LAZY связан с тем, что по умолчанию используется Тип выборки.НЕТЕРПЕЛИВЫЙ это очень плохо сказывается на производительности .

Теперь давайте предположим, что у нас есть следующая Запись сущность в нашей базе данных:

Post post = new Post();
post.setId(1L);
post.setTitle("High-Performance Java Persistence");

entityManager.persist(post);

Если вы хотите получить объект, чтобы связанный SQL запрос select был выполнен сразу, вам необходимо использовать метод find текущего EntityManager :

Post post = entityManager.find(Post.class, 1L);

assertEquals("High-Performance Java Persistence", post.getTitle());

Если вы просмотрите журнал запросов, вы увидите, что SQL-запрос выполняется вызовом метода find :

SELECT p.id AS id1_0_0_,
       p.title AS title2_0_0_
FROM   post p
WHERE p.id = 1

Если вам нужно, чтобы объект Post был извлечен, потому что вам нужно получить доступ к его свойствам, то метод find является правильным для вызова.

Однако давайте предположим, что мы хотим создать Комментарий к сообщению и нам нужна сущность Post , чтобы установить базовый post_id Внешний ключ.

Если мы используем метод find , как в следующем примере:

PostComment comment = new PostComment();
comment.setReview("Just awesome!");

Post post = entityManager.find(Post.class, 1L);
comment.setPost(post);

entityManager.persist(comment);

Hibernate создаст следующие инструкции SQL:

SELECT p.id AS id1_0_0_,
       p.title AS title2_0_0_
FROM   post p
WHERE p.id = 1

INSERT INTO post_comment (post_id, review, id)
VALUES (1, 'Just awesome!', 1)

Запрос SELECT на этот раз бесполезен, потому что нам не нужно извлекать объект Post . Мы хотим только установить базовый столбец post_id Внешний ключ.

Чтобы исправить предыдущую проблему, мы можем использовать метод getReference :

PostComment comment = new PostComment();
comment.setReview("Just awesome!");

Post post = entityManager.getReference(Post.class, 1L);
comment.setPost(post);

entityManager.persist(comment);

И на этот раз Hibernate выдаст только инструкцию INSERT:

INSERT INTO post_comment (post_id, review, id)
VALUES (1, 'Just awesome!', 1)

В отличие от find , getReference возвращает только прокси-сервер сущности , у которого установлен только идентификатор. Если вы получите доступ к Прокси-серверу, соответствующая инструкция SQL будет активирована до тех пор, пока EntityManager все еще открыт.

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

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

Понимание того, какие операции связаны с каждым переходом состояния сущности, имеет первостепенное значение при использовании JPA и Hibernate.

Поэтому, когда вам нужно установить @ManyToOne или @OneToOne отношения, метод getReference намного эффективнее, если вам не нужно извлекать связанную родительскую запись.