获取 EAGER 获取对象 OneToOne 时出现 LazyInitializationException
LazyInitializationException when get EAGER fetch object OneToOne
我有两个实体
@Entity
@Table(name = "user")
@Data
@Builder
@EqualsAndHashCode(callSuper=false)
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String name;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@PrimaryKeyJoinColumn
private UserLastLogin userLastLogin;
}
@Entity
@Table(name = "lastLogin")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(onlyExplicitlyIncluded = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserLastLogin implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String userName;
@Column(name = "date")
private LocalDateTime date;
@OneToOne
@MapsId
@JoinColumn(name = "name")
private User user;
}
我使用 spring 引导,使用 spring 数据和 jpa,在最新版本中休眠。
在文档中,@OneToOne 是默认的 EAGER,但是当我获取急切的获取对象时,当我在 get 方法中不使用 @Transactional 时,我会得到 lazyInitializationException。我不明白为什么...
public UserDto getUser(String userName) {
var user= userRepository.getById(userName);
d.getSystemUserLastLogin(); // this throw lazy initialization exception
return mapper.entityToDto(d);
}
当我将此方法标记为@Transactioal 时,这项工作。但是,不推荐在 get 方法中使用 transactions。我需要在此关系中使用 EAGER fetch。
当我查看查询休眠时,我有一个 select,但子对象不可用。
Hibernate:
select
user0_.name as nazwa1_4_0_,
user2_.name as name1_23_2_,
user2_.data as data3_23_2_
from
user0_
left outer join
last_login user2_
on user0_.name=user2_.name
where
user0_.name=?
我建议您使用辅助表,而不是像这样:
@Entity
@Table(name = "user")
@Data
@Builder
@EqualsAndHashCode(callSuper=false)
@ToString
@AllArgsConstructor
@NoArgsConstructor
@SecondaryTable(name = "lastLogin", pkJoinColumns = @PrimaryKeyJoinColumn(name = "name"))
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String name;
@Column(table = "lastLogin", name = "date")
private LocalDateTime date;
}
有关详细信息,另请参阅 https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables。
问题是尽管使用了 eager 获取,但使用了 lazy。这是由于使用了存储库中的 getById 方法,该方法仅检索对象的引用并在检索延迟时捕捉所有字段。更改为 findById 解决了问题,因为 findById 需要一个对象,而不是一个引用。
我有两个实体
@Entity
@Table(name = "user")
@Data
@Builder
@EqualsAndHashCode(callSuper=false)
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String name;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@PrimaryKeyJoinColumn
private UserLastLogin userLastLogin;
}
@Entity
@Table(name = "lastLogin")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(onlyExplicitlyIncluded = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserLastLogin implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String userName;
@Column(name = "date")
private LocalDateTime date;
@OneToOne
@MapsId
@JoinColumn(name = "name")
private User user;
}
我使用 spring 引导,使用 spring 数据和 jpa,在最新版本中休眠。 在文档中,@OneToOne 是默认的 EAGER,但是当我获取急切的获取对象时,当我在 get 方法中不使用 @Transactional 时,我会得到 lazyInitializationException。我不明白为什么...
public UserDto getUser(String userName) {
var user= userRepository.getById(userName);
d.getSystemUserLastLogin(); // this throw lazy initialization exception
return mapper.entityToDto(d);
}
当我将此方法标记为@Transactioal 时,这项工作。但是,不推荐在 get 方法中使用 transactions。我需要在此关系中使用 EAGER fetch。
当我查看查询休眠时,我有一个 select,但子对象不可用。
Hibernate:
select
user0_.name as nazwa1_4_0_,
user2_.name as name1_23_2_,
user2_.data as data3_23_2_
from
user0_
left outer join
last_login user2_
on user0_.name=user2_.name
where
user0_.name=?
我建议您使用辅助表,而不是像这样:
@Entity
@Table(name = "user")
@Data
@Builder
@EqualsAndHashCode(callSuper=false)
@ToString
@AllArgsConstructor
@NoArgsConstructor
@SecondaryTable(name = "lastLogin", pkJoinColumns = @PrimaryKeyJoinColumn(name = "name"))
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "name")
private String name;
@Column(table = "lastLogin", name = "date")
private LocalDateTime date;
}
有关详细信息,另请参阅 https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables。
问题是尽管使用了 eager 获取,但使用了 lazy。这是由于使用了存储库中的 getById 方法,该方法仅检索对象的引用并在检索延迟时捕捉所有字段。更改为 findById 解决了问题,因为 findById 需要一个对象,而不是一个引用。