Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在Hibernate中使用JPA标准API摆脱N+1_Java_Hibernate_Jpa_Hibernate Criteria_Criteria Api - Fatal编程技术网

Java 如何在Hibernate中使用JPA标准API摆脱N+1

Java 如何在Hibernate中使用JPA标准API摆脱N+1,java,hibernate,jpa,hibernate-criteria,criteria-api,Java,Hibernate,Jpa,Hibernate Criteria,Criteria Api,我正在将我们的DAO从使用Hibernate标准API迁移到JPA标准API。我有一节课有几个@ManyToOne: 在查询中,我使用JoinType.LEFT来消除默认生成的交叉联接: 我得到了正确的结果,所有的A和B记录都被正确检索。然而,在迁移之后,我遇到了一个n+1问题:尽管在生成的查询中使用了左外部连接,但所有的B记录都是逐个检索的。以前,当使用Hibernate标准API时,Hibernate能够满足查询,而不需要n+1在生成的SQL中具有相同的联接 谢谢你的任何想法和帮助 作为使用

我正在将我们的DAO从使用Hibernate标准API迁移到JPA标准API。我有一节课有几个@ManyToOne:

在查询中,我使用JoinType.LEFT来消除默认生成的交叉联接:

我得到了正确的结果,所有的A和B记录都被正确检索。然而,在迁移之后,我遇到了一个n+1问题:尽管在生成的查询中使用了左外部连接,但所有的B记录都是逐个检索的。以前,当使用Hibernate标准API时,Hibernate能够满足查询,而不需要n+1在生成的SQL中具有相同的联接

谢谢你的任何想法和帮助

作为使用上述if-else进行b1.fieldName搜索的示例,我将得到以下结果:

criteriaBuilder.equal(root.join("b1", JoinType.LEFT).get("someFiled"), 42)

N+1问题来自@manytone关联的默认抓取策略

因此,您需要切换到FetchType.LAZY,如下所示:

@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '1' OR B.B_CODE = '2') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b1;

@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '3' OR B.B_CODE = '4') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b2;
如果要自动检测可能影响应用程序其他部分的N+1问题,则可以使用

如果您迫切需要使用criteriaapi获取关联,那么应该使用fetch而不是join


您还应该提供JPA代码。你用的是哪种类型的提取方法?@NiVeR实际上,我用的是。加入。它在我刚才使用的问题的if-else分支中。如果遇到,请加入,例如,按b1.someField搜索。它与criteriaBuilder.equalroot.joinb1、JointType.LEFT.getsomeField相同,42您可以使用fetch join better或@BatchSizesize=x@Samoth好主意。但它是“许多人”。我应该使用@BatchSizesize=1吗?关于fetchjoin:它总是很渴望的,对吗?你的意思是。获取方法还是一些注释?是的,它会很急切。您可以在HQL中使用它,例如从用户u中选择u加入获取u地址。BatchSize for ManyToOne:谢谢,它非常有用,尤其是这篇文章。但我得去拿唱片。我设法在CriteriaQuery的根上使用.fetch解决了这个问题,然后您应该使用fetch而不是join。否则它会生成交叉联接。我必须按预期使用bothworks,谢谢!除了path=From path.fetchfield之外,JoinType.LEFT;-。fetch返回fetch,但它不编译
criteriaBuilder.equal(root.join("b1", JoinType.LEFT).get("someFiled"), 42)
@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '1' OR B.B_CODE = '2') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b1;

@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '3' OR B.B_CODE = '4') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b2;
if (LEFT_OUTER_JOIN_ENTITIES.contains(field)) {
    path = ((From) path).fetch(field, JoinType.LEFT);
} else {
    path = path.get(field);
}