代码之家  ›  专栏  ›  技术社区  ›  AlanObject

我可以将JPA集合缩放多远(地图或列表)

  •  0
  • AlanObject  · 技术社区  · 9 年前

    我正在通过JPA实现一个由SQL数据库支持的在线文件系统。对于目录层次结构,我创建了一个如下所示的实体:

    @Entity
    @Table(name = "PATH")
    public class Path extends BaseObject implements Serializable {
    
        @Column(nullable = false)
        private String name;
    
        @ManyToOne
        private BaseObject reference;
    
        @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true)
        @MapKey(name = "name")
        private Map<String, Path> members;
    
        @ManyToOne
        private Path parent;
    
        //etc
    

    这工作得非常好。根节点是 路径 实例,其中 父母亲 为空。有了这个方案,我可以尽可能轻松地进行树的上下遍历和查找。

    问题是这可以扩展到什么程度。例如,我的一个根路径实例将为系统的每个用户拥有一个成员。对于几十个甚至几百个用户来说,这很好,如果我的网站吸引了几万甚至几十万用户,会发生什么?

    如果必须的话,我可以放弃 成员 列并使用SQL查找成员节点 选择 但我讨厌那样做。是否有任何准则来确定这一数字有多大 地图 结构必须在变得不切实际之前得到改善?

    1 回复  |  直到 9 年前
        1
  •  1
  •   JB Nizet    9 年前

    这个 members 默认情况下,关联是懒惰的。因此,加载Path时不会发生任何错误,直到……您开始使用此 成员 字段(即对其调用任何方法)。然后,成千上万的孩子将被载入记忆,而这根本无法很好地扩展。但是使用专用查询不会更好:成千上万的孩子也会被加载到内存中。

    问题是……您应该避免在内存中加载路径的所有子级。使用现有父级创建新路径时不需要这样做。您可能必须这样做才能在屏幕上显示路径的所有子级,但如果您有数千个,这是不现实的,因此您最好使用分页查询以20或50的切片显示它们。

    所以,我真的会抛弃这种过于危险的一对多关联,使用特别查询来获取您需要的孩子,分片进行。我更关心的是与家长的联系。由于您已将它们定义为急切加载(这是toOne关联的默认值),因此每次加载路径时,JPA都会加载其父级、祖级、外祖级等,直到根。如果你的树很深,这可能会有问题。您最好将关联定义为懒惰(我基本上为所有关联都这样做)。

    最后,请注意您的映射不正确。你在这里有一个双向关联,并且OneToMany 成员 因此是ManyToOne的反面 parent ,因此应使用

    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    
    推荐文章