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 提供程序允许您:
创建在您的实体路径中导航的 JPA 查询。
为您将实体加载到内存中,无需您自己 creating/executing 其他查询,只需访问任何实体上的 getter 或 setter ...
“性能问题”可能会出现,具体取决于您的用例、您的数据有多大、您访问数据的方式以及其他条件(顺便说一句,我引用是因为可能还要多几秒钟不可能成为你的瓶颈)...让我给你举几个例子。
假设我们的实体是:Department
和 Employee
...一个 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)
如您所见,问题和解决方案与业务案例密切相关。
总而言之,
使用注释,并使用您计划在生产中遇到的数据样本进行一些测试,运行你的号码。根据经验,让您的人际关系 fetch=LAZY
.
始终是个好主意
如果您认为存在性能问题,请先启用 JPA 提供程序调试模式。它会向您显示正在执行的查询,它会帮助您检测您面临的问题...
确定问题后,开始根据您的业务案例提出解决方案。请记住,没有灵丹妙药或放之四海而皆准的解决方案,因此正确的解决方案将与您的用例相关联...
假设我有实体 A,它带有 @OneToMany 注释,引用了具有 @ManyToOne 注释的 class B,即 B 是 A 的 child。
child人多了可以建模吗?说成千上万......例如我有一个 table B 有 6000 行,外键到 table A 。 JPA 是否使用 @OneToMany suitable 来完成这项工作?
简短的回答是:这取决于 ...
此类注释仅声明您的实体如何连接以及它们如何相互依赖(与多少行无关在表格中)...使用它们时,JPA 提供程序允许您:
创建在您的实体路径中导航的 JPA 查询。
为您将实体加载到内存中,无需您自己 creating/executing 其他查询,只需访问任何实体上的 getter 或 setter ...
“性能问题”可能会出现,具体取决于您的用例、您的数据有多大、您访问数据的方式以及其他条件(顺便说一句,我引用是因为可能还要多几秒钟不可能成为你的瓶颈)...让我给你举几个例子。
假设我们的实体是:Department
和 Employee
...一个 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)
如您所见,问题和解决方案与业务案例密切相关。
总而言之,
使用注释,并使用您计划在生产中遇到的数据样本进行一些测试,运行你的号码。根据经验,让您的人际关系
始终是个好主意fetch=LAZY
.如果您认为存在性能问题,请先启用 JPA 提供程序调试模式。它会向您显示正在执行的查询,它会帮助您检测您面临的问题...
确定问题后,开始根据您的业务案例提出解决方案。请记住,没有灵丹妙药或放之四海而皆准的解决方案,因此正确的解决方案将与您的用例相关联...