繁体   English   中英

Hibernate @OneToOne 已加载,即使是懒惰的

[英]Hibernate @OneToOne loaded even though is lazy

我正在使用 Spring Boot 2.3、Spring 数据和 Hibernate。

我有以下实体

@Entity
@Getter
@Setter
@EqualsAndHashCode(of = "id")
public class User {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;

    private String name;

    @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private Address address;

    @Version
    private Long version;
}

@Entity
@Getter
@Setter
@EqualsAndHashCode(of = "id")
public class Address {

    @Id
    private Long id;

    private String fullAddress;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id")
    @MapsId
    private User user;

    @Version
    private Long version;    
}

执行以下代码时,将执行与用户存储库相关的任何查询(对我来说这是预期的行为)。

Address addressFromDb = addressRepository.findAll().get(0);
log.info("" + addressFromDb.getUser().getId());

// select address0_.id as id1_0_, address0_.full_address as full_add2_0_, address0_.version as version3_0_ from address address0_

但是当我执行以下代码时,会有多个查询,我不明白为什么。 显然,从用户到地址的FetchType.LAZY不受尊重。

User userFromDb = userRepository.findAll().get(0);

// select user0_.id as id1_4_, user0_.name as name2_4_, user0_.version as version3_4_ from user user0_
// select address0_.id as id1_0_0_, address0_.full_address as full_add2_0_0_, address0_.version as version3_0_0_ from address address0_ where address0_.id=?

我错过了什么?

为了更有帮助和更清楚,我创建了以下github repo

Hibernate (或更具体地说是PersistenceContext )需要知道实体是否存在,以便它可以决定是为实体提供代理还是null 这不适用于XToMany关系,因为整个集合可以包装在代理中,在特殊情况下它将为空。

还需要指出的是, FetchType只是对 JPa 实现的建议,不能保证在任何情况下都会实现。 您可以在此处阅读有关@OneToOne的更多信息,尤其是在获取策略方面:

虽然可以延迟获取单向 @OneToOne 关联,但双向 @OneToOne 关联的父端却不能。 即使指定关联不是可选的并且我们有 FetchType.LAZY,父端关联的行为也类似于 FetchType.EAGER 关系。 EAGER fetching 很糟糕。

即使 FK 不是 NULL 并且父端通过可选属性(例如 @OneToOne(mappedBy = "post", fetch = FetchType.LAZY, optional = false))知道其不可为空性,Hibernate 仍然会生成二级 select 语句。

对于每一个托管实体,Persistence Context 都需要实体类型和标识符,因此在加载父实体时必须知道子标识符,而找到关联的 post_details 主键的唯一方法是执行二级查询。

字节码增强是唯一可行的解决方法。 但是,它仅在父端使用 @LazyToOne(LazyToOneOption.NO_PROXY) 注释并且子端未使用 @MapsId 时才有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM