【问题标题】:What's the JPA equivalent of the Hibernate @LazyToOne annotation?Hibernate @LazyToOne 注释的 JPA 等价物是什么?
【发布时间】:2013-05-06 04:00:55
【问题描述】:

我目前正在使用 Hibernate @LazyToOne 注释。

由于我从 Hibernate 切换到 JPA,我想知道 @LazyToOne 在 JPA 中是否可用,或者是否有任何其他注释在 JPA 中提供相同的功能?

【问题讨论】:

  • @ManyToOne(fetch = FetchType.LAZY) 像这样。

标签: java hibernate jpa orm lazy-loading


【解决方案1】:

@LazyToOneLazyToOneOption

旧版@LazyToOne 注释提供以下选项:

  • FALSE
  • PROXY
  • NO_PROXY

LazyToOneOption.FALSE

FALSE 选项等效于 JPA 的 FetchType.EAGER 注释,因此应避免使用它,因为它可能会导致严重的性能问题。

LazyToOneOption.PROXY

PROXY 选项等效于 JPA [FetchType.LAZY] 策略。但是,您应该更喜欢使用 JPA @OneToOne@ManyToOne 关联的 fetch 属性。

LazyToOneOption.NO_PROXY

在父端使用@OneToOne 关联时,此策略很有用。

所以,假设您有以下 PostPostDetails 实体:

如果Post映射了这个一对一表关系的父端:

@OneToOne(
    mappedBy = "post",
    fetch = FetchType.LAZY,
    cascade = CascadeType.ALL
)
private PostDetails details;

即使关联使用FetchType.LAZY策略,我们可以看到如果我们要获取Post实体:

Post post = doInJPA(entityManager -> {
    return entityManager.find(Post.class, 1L);
});

PostDetails 将被急切地获取:

SELECT p.id AS id1_0_0_,
       p.title AS title2_0_0_
FROM post p
WHERE p.id = 1
 
SELECT pd.id AS id1_1_0_,
       pd.created_by AS created_2_1_0_,
       pd.created_on AS created_3_1_0_
FROM post_details pd
WHERE pd.id = 1

这是因为 Hibernate 不知道如何初始化 details 属性,因为它需要决定是使用 null 还是代理,而找出这一点的唯一方法是发出 SELECT 查询。

所以,要解决这个问题,我们需要做以下事情:

  • 启用延迟获取字节码增强功能
  • 使用NO_PROXY 策略

要启用延迟加载字节码增强功能,我们可以使用这个 Hibernate Maven 插件:

<plugin>
    <groupId>org.hibernate.orm.tooling</groupId>
    <artifactId>hibernate-enhance-maven-plugin</artifactId>
    <version>${hibernate.version}</version>
    <executions>
        <execution>
            <configuration>
                <enableLazyInitialization>true</enableLazyInitialization>
            </configuration>
            <goals>
                <goal>enhance</goal>
            </goals>
        </execution>
    </executions>
</plugin>

而且,我们还需要使用NO_PROXY 策略:

@OneToOne(
    mappedBy = "post",
    fetch = FetchType.LAZY,
    cascade = CascadeType.ALL
)
@LazyToOne(LazyToOneOption.NO_PROXY)
private PostDetails details;

随着这一变化的到位,父端@OneToOne 关联将被延迟获取。

【讨论】:

    【解决方案2】:

    你可以使用:

    @OneToOne(fetch = FetchType.LAZY)
    

    这个问题的更多细节: Making a OneToOne-relation lazy

    【讨论】:

    • 这和@LazyToOne不一样,除非你还设置了optional=true,可为空的一对一引用总是急切的
    • 你的意思是 optional=false?
    【解决方案3】:

    你可以创建一个jpql,比如:

    User user = em.createQuery("SELECT NEW com.model.User(u.id, u.name, u.password)
        FROM User u WHERE u.id = :id", User.class)
            .setParameter("id", 1L)
            .gerSingleResult();`
    

    它可能会解决您的问题。但是,您必须记住编写默认构造函数。

    【讨论】:

      【解决方案4】:

      应该是

      @OneToOne(fetch = FetchType.LAZY, optional=false)
      

      在这个论坛上找到:https://forum.hibernate.org/viewtopic.php?p=2388783

      我想,原因是 JPA 知道一个属性是否已经被获取的唯一方法是检查它是否有一个值,但如果 null 是一个有效值,那么就没有办法知道了。因此,无论如何总是会获取可选属性。

      【讨论】:

        猜你喜欢
        • 2021-06-28
        • 2011-11-06
        • 2014-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多