我正在通过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 SELECT 操作的成员节点,但我讨厌这样做。是否有任何指导方针可以确定 Map 结构在变得不切实际之前必须达到多大?
答案 0 :(得分:1)
默认情况下,members
关联是懒惰的。所以在加载Path时不会发生任何不好的事情,直到......你开始使用这个members
字段(即调用它上面的任何方法)。然后成千上万的孩子将被装入记忆中,并且根本不会很好地扩展。但使用专用查询不会更好:成千上万的孩子也会被加载到内存中。
问题在于......你应该简单地避免在内存中加载路径的所有子节点。您不需要这样做来创建具有现有父级的新路径。您可能必须这样做才能在屏幕上显示路径的所有子项,但如果您有数千个这样的子项,那么这是不现实的,因此您最好使用分页查询通过切片显示它们20或50。
所以,我确实会放弃这个过于危险的OneToMany关联,并使用即席查询来获取所需的子项。我更关心的是与父母的联系。由于您已将它们定义为急切加载(这是toOne关联的默认值),因此每次加载路径时,JPA都会加载其父级,祖父级和祖父级等,直到根。如果树很深,这可能会有问题。您最好将关联定义为懒惰(基本上所有关联都是这样做的。)
最后,请注意您的映射不正确。你在这里有一个双向关联,OneToMany members
因此是ManyToOne parent
的反面,所以它应该用
@OneToMany(mappedBy = "parent", orphanRemoval = true)