我正在使用Spring 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回购
发布于 2020-06-07 17:23:59
Hibernate (或者更确切地说是PersistenceContext)需要知道实体是否存在,以便它可以决定是为实体提供代理还是为null提供代理。这不适用于XToMany关系,因为整个集合可以包装在代理中,在特殊情况下它将是空的。
同样重要的是要指出,FetchType只是对JPa实现的一个建议,没有任何保证,在每一种情况下,它都将得到实现。您可以阅读更多关于@OneToOne 这里的信息,特别是在获取策略方面:
虽然单向@OneToOne关联可以懒洋洋地获取,但是双向@OneToOne关联的父端则不是。即使在指定关联不是可选的并且我们有FetchType.LAZY时,父端关联的行为也类似于FetchType.EAGER关系。而渴望的诱惑是不好的。 即使FK不是NULL,并且父端通过可选属性(例如@OneToOne(mappedBy = "post",fetch = FetchType.LAZY,可选= false))知道它的非空性,Hibernate仍然生成一个辅助select语句。 对于每个托管实体,持久性上下文都需要实体类型和标识符,因此在加载父实体时必须知道子标识符,找到关联的post_details主键的唯一方法是执行辅助查询。 字节码增强是唯一可行的解决办法。但是,只有当父端被@LazyToOne(LazyToOneOption.NO_PROXY)注释并且子端不使用@MapsId时,它才能工作。
https://stackoverflow.com/questions/62248951
复制相似问题