2017-08-08 54 views
0

我有一个问题,加载我的懒集合会产生大量的SQL语句,我不知道是否没有更有效的方式来加载数据。用hibernate/spring一次加载所有懒集合

现状:

家长儿童叫孩子的懒惰集合。它实际上是一个多对多的关系。

我加载的家长个清单,一个CrudRepository,我需要得到所有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

如果你只需要父母与孩子的所有的ID对每个父母,为什么不直接使用基于JDBC的DAO(使用'JdbcTemplate',例如)此方法,写一个简单的SQL像'选择PARENT_ID,child_id父母,孩子们加入......'? –

+0

显示您的代码请..实体,回购,使用例如与坏的结果...... – Cepr0

+0

当我们谈论亲子,它应该是一个一对多.. –

回答

1

这背后懒收藏:)

含义,如果该集合的吸气剂被称为延迟集合才会被查询的整体思路,你”不言而喻的是,你加载所有的实体和东西(代码,框架,无论什么)都会调用该实体的getChildren(假设);这将产生这些查询。

现在,如果这种情况总是发生,那么首先,懒惰的收集没有意义,将它们设置为 EAGER - 编辑:正如在评论中说,EAGER很少是解决方案,在这种情况下,特别是它看起来并不像它,加入虽然:)

无论哪种方式,对你的情况,将无济于事,你想要的是一次我承担加载所有的数据,对于这一点,当你查询你必须做出的加入明确的,例如与JPQL:

SELECT p FROM Parent p LEFT JOIN FETCH p.children 
+1

使用EAGER很少是正确的解决方案。有太多的情况,它仍然会产生n + 1个查询。我宁愿建议做连接抓取等 –

+0

从来都是一个强烈的字眼:)但是,是的,在这种情况下,最有可能并非如此。将编辑答案 –

+0

eheheheh :)足够公平:) –

1

作为另一个答案建议,JOIN FETCH通常是解决类似问题的方法。内部用于加入提取的内容是生成的SQL将包含加入提取实体的列。

但是,你不应该盲目地认为join-fetch是万能的。

一个常见的情况是您想要检索具有2个一对多关系的实体。例如,你有User,每个User可能有多个AddressPhone

如果你天真地在您的查询做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的数量并不总是意味着更好的性能。在某些情况下,分解查询可能会提高性能。