我有一个问题,加载惰性集合会产生大量 SQL 语句,我想知道是否没有更有效的方法来加载数据。
情况:
Parent 有一个名为 Children 的惰性集合 Child。它实际上是一个多对多的关系。
我使用 CrudRepository 加载一个Parent列表,并且我需要获取每个Parent的所有child_ids。因此,每次访问子集合时,我都会执行一个新的 SQL 语句。
如果我加载 200 个 parent ,则会执行 201 个查询(1 个用于 parent 列表,1 个用于每个 parent 的 child )。
知道如何仅通过一个查询加载数据吗?
编辑 1
“父/子”在这里可能是一个不好的命名。事实上,我有一个多对多关系。
这是一些代码:
@Entity
public class Tour {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name="system-uuid",
strategy = "uuid2")
@Column(length = 60)
private String id;
@ManyToMany
@JoinTable(
name="parent_images",
joinColumns = @JoinColumn(name="tour_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name="image_id", referencedColumnName = "id"),
foreignKey = @ForeignKey(name = "FK_TOUR_IMAGE_TOUR"),
inverseForeignKey = @ForeignKey(name = "FK_TOUR_IMAGE_IMAGE")
)
private List<Image> images = new ArrayList<>();
}
@Entity
public class Image {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name="system-uuid",
strategy = "uuid2")
@Column(length = 40)
private String id;
//....
}
// Code to fetch:
@Autowired
TourRepository repo;
List<Tour> tours = repo.findBy(....);
List<String> imageIds = new ArrayList<>();
for(Tour tour : tours){
imageIds.addAll(tour.getImages().stream().map(b -> b.getId()).collect(Collectors.toList()));
}
最佳答案
正如另一个答案所建议的,JOIN FETCH
通常是解决类似问题的方法。 join-fetch 内部发生的情况是,生成的 SQL 将包含 join-fetched 实体的列。
但是,您不应该盲目地将 join-fetch 视为万能药。
一种常见的情况是您想要检索具有 2 个一对多关系的实体。例如,您有用户
,每个用户
可能有多个地址
和电话
如果你天真地执行from User user join fetch user.phones join fetch users.addresses
,Hibernate将报告你的查询中的问题,或者生成一个低效的查询,其中包含地址和地址的笛卡尔积电话。
在上述情况下,一种解决方案是将其分解为多个查询:
from User user join fetch user.phones where ....
后跟 from User user join fetch user.addresses where ....
。
请记住:SQL 数量较少并不总是意味着性能更好。在某些情况下,分解查询可能会提高性能。
关于java - 使用 hibernate/spring 一次加载所有惰性集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45576330/