JPA一对多有很多孩子

JPA one to many with many childern

假设我有实体 A,它带有 @OneToMany 注释,引用了具有 @ManyToOne 注释的 class B,即 B 是 A 的 child。

child人多了可以建模吗?说成千上万......例如我有一个 table B 有 6000 行,外键到 table A 。 JPA 是否使用 @OneToMany suitable 来完成这项工作?

简短的回答是:这取决于 ...

此类注释仅声明您的实体如何连接以及它们如何相互依赖(与多少行无关在表格中)...使用它们时,JPA 提供程序允许您:

  1. 创建在您的实体路径中导航的 JPA 查询。

  2. 为您将实体加载到内存中,无需您自己 creating/executing 其他查询,只需访问任何实体上的 getter 或 setter ...

“性能问题”可能会出现,具体取决于您的用例、您的数据有多大、您访问数据的方式以及其他条件(顺便说一句,我引用是因为可能还要多几秒钟不可能成为你的瓶颈)...让我给你举几个例子。

假设我们的实体是:DepartmentEmployee ...一个 Department 可以有多个 Employees(因此它将有一个 Employees 列表注释as @OneToMany) ... Employee 只能在一个 Department 中工作(因此它将有一个部门 属性 注释为 @ManyToOne) ...

您可能遇到的加载问题:

问题 #1:您需要从数据库加载一个 Employee ...默认情况下,@ManyToOne 有一个 EAGER fetch 计划,这意味着一旦您加载 Employee,JPA 提供程序也会为您加载其关联的 Department(为此,它将执行另一个查询)。这里的问题是您的用例可能不需要 Department 信息,并且 JPA 提供程序无缘无故地访问数据库。 解决方案:将@ManyToOne标记为获取LAZY

问题 #2:您将 @ManyToOne 标记为提取 LAZY,但您有一个业务案例,您确实需要 Employee 加上他的 Department 信息...您想在一次数据库访问(仅一次查询)中完成此操作,并避免 JPA 提供程序在问题 #1 中所做的事情。 解决方案:您可以使用 fetch 图加载 Employee 实体。

问题 #3:您正在加载一组 Employees,您需要访问他们的 Department 信息...您加载这样的组和每个员工,您访问他的部门:employees.stream().map(Employee::getDepartment) ... 您注意到 JPA 提供程序调用数据库 N 次以上以获取部门信息......这称为:N+1 problem (您可以搜索它)...解决方案:使用获取图形或配置 JPA 提供程序以使用 .

加载实体

问题 #4:您需要加载一个 Department 并访问它的所有 Employees ...您注意到这样做:department.getEmployees(),需要一些时间才能将所有数据加载到内存中。 解决方案:检查你的数据库模型,可能需要在里面有一些索引。

问题 #5:你需要加载一个 Department 并访问它的所有 Employees ...你有索引和所有,但你确定这些表有数百万行......您不需要一次加载所有数据,因为它可能会产生 OutOfMemoryProblems解决方案:通过循环和使用批量策略加载 Employees(参见 MaxResults and FirstResult

如您所见,问题和解决方案与业务案例密切相关。

总而言之,

  1. 使用注释,并使用您计划在生产中遇到的数据样本进行一些测试,运行你的号码。根据经验,让您的人际关系 fetch=LAZY.

    始终是个好主意
  2. 如果您认为存在性能问题,请先启用 JPA 提供程序调试模式。它会向您显示正在执行的查询,它会帮助您检测您面临的问题...

  3. 确定问题后,开始根据您的业务案例提出解决方案。请记住,没有灵丹妙药或放之四海而皆准的解决方案,因此正确的解决方案将与您的用例相关联...