我有一个问题,加载我的懒惰集合会产生大量的SQL语句,我想知道是否没有更有效的方法来加载数据。
情况:
Parent 有一个名为children的 Child 的惰性集合。它实际上是一种多对多的关系。
我使用CrudRepository加载 Parent 的列表,我需要为每个 Parent 获取所有child_ids。所以每次我访问子集合时,我都会执行一个新的SQL语句。
如果我加载了200个父母,则会执行201个查询(1个表示父母列表,1个表示每个父母的孩子)。
知道如何只用一个查询加载数据吗?
编辑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()));
}
答案 0 :(得分:1)
这是懒惰集合背后的整个想法:)
意思是,只有在调用该集合的getter时才会查询一个惰性集合,你所说的是你加载所有实体和某些东西(代码,框架,等等)调用getChildren
(假设)该实体;这将产生这些查询。
现在,如果这种情况总是发生,那么首先,有一个懒惰的集合没有意义,将它们设置为 - 编辑:如评论中所述, EAGER很少是解决方案,在这种情况下,特别是肯定看起来不是这样,但是加入是:)EAGER
。
无论哪种方式,对于你的情况都无济于事,你想要的是一次加载所有数据我假设,为此,当你进行查询时你必须使连接显式,例如使用JPQL:
SELECT p FROM Parent p LEFT JOIN FETCH p.children
答案 1 :(得分:1)
正如另一个答案所示,JOIN FETCH
通常是解决类似问题的方法。 join-fetch内部发生的是生成的SQL将包含join-fetched实体的列。
但是,你不应盲目对待加入 - 获取是灵丹妙药。
一种常见情况是您想要检索具有2个一对多关系的实体。例如,您有User
,每个User
可能有多个Address
和Phone
如果您天真地做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数并不总是意味着更好的性能。在某些情况下,分解查询可能会提高性能。