Java 如何在Hibernate中使用JPA标准API摆脱N+1
我正在将我们的DAO从使用Hibernate标准API迁移到JPA标准API。我有一节课有几个@ManyToOne: 在查询中,我使用JoinType.LEFT来消除默认生成的交叉联接: 我得到了正确的结果,所有的A和B记录都被正确检索。然而,在迁移之后,我遇到了一个n+1问题:尽管在生成的查询中使用了左外部连接,但所有的B记录都是逐个检索的。以前,当使用Hibernate标准API时,Hibernate能够满足查询,而不需要n+1在生成的SQL中具有相同的联接 谢谢你的任何想法和帮助 作为使用上述if-else进行b1.fieldName搜索的示例,我将得到以下结果: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中具有相同的联接 谢谢你的任何想法和帮助 作为使用
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);
}