Hibernate left join 总是命中底部
Hibernate left join always hit the base
我有下一个服务:
public void checkAll() {
Session sess = (Session) em.getDelegate();
System.out.println("Check 1");
Query query = sess.createQuery("select distinct t from House t left join fetch Kw k on t.id=k.fkHouse "
+ "left join fetch Kart a on k.id=a.fkKw "
+ "left join fetch Reg r on a.lsk=r.lsk "
+ "left join fetch RegState s on a.lsk=s.lsk "
+ " "
+ "where t.klsk = 187804");
System.out.println("Check 2");
List<House> lst =query.list();
for (House o : lst) {
System.out.println("Check 3");
for (Kw kw : o.getKw()) {
for (Kart kart : kw.getLsk()) {
for (Reg reg : kart.getReg()) {
System.out.print("Reg="+reg.getDtReg());
break;
}
break;
}
break;
}
break;
}
System.out.println("Check 4");
}
我已经打开 SQL Hibernate 的调试,接下来请看:
Check 1
2393 [main] INFO org.hibernate.hql.internal.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
Check 2
2547 [main] DEBUG org.hibernate.SQL - select distinct house0_.ID as ID1_1_, house0_.FK_K_LSK as FK_K_LSK2_1_, house0_.FK_STREET as FK_STREET3_1_ from AR.HOUSE house0_ left outer join AR.KW kw1_ on (house0_.ID=kw1_.FK_HOUSE)left outer join AR.KART kart2_ on (kw1_.ID=kart2_.FK_KW)left outer join PS.REG reg3_ on (kart2_.LSK=reg3_.LSK)left outer join PS.REG_STATE regstate4_ on (kart2_.LSK=regstate4_.LSK) where house0_.FK_K_LSK=187804
Check 3
2609 [main] DEBUG org.hibernate.SQL - select kw0_.FK_HOUSE as FK_HOUSE3_3_0_, kw0_.ID as ID1_3_0_, kw0_.ID as ID1_3_1_, kw0_.FK_K_LSK as FK_K_LSK2_3_1_, kw0_.FK_HOUSE as FK_HOUSE3_3_1_ from AR.KW kw0_ where kw0_.FK_HOUSE=?
2655 [main] DEBUG org.hibernate.SQL - select kart0_.FK_KW as FK_KW4_2_0_, kart0_.LSK as LSK1_2_0_, kart0_.LSK as LSK1_2_1_, kart0_.FK_K_LSK as FK_K_LSK2_2_1_, kart0_.FIO as FIO3_2_1_, kart0_.FK_KW as FK_KW4_2_1_ from AR.KART kart0_ where kart0_.FK_KW=?
2657 [main] DEBUG org.hibernate.SQL - select reg0_.LSK as LSK6_15_0_, reg0_.ID as ID1_15_0_, reg0_.ID as ID1_15_1_, reg0_.DT_REG as DT_REG2_15_1_, reg0_.DT_REG_TS as DT_REG_TS3_15_1_, reg0_.DT_UNREG as DT_UNREG4_15_1_, reg0_.DT_UNREG_TS as DT_UNREG_TS5_15_1_, reg0_.LSK as LSK6_15_1_, reg0_.FK_PERS as FK_PERS7_15_1_, reg0_.FK_REG_STATUS as FK_REG_STATUS8_15_1_, reg0_.FK_REG_TP as FK_REG_TP9_15_1_ from PS.REG reg0_ where reg0_.LSK=?
Reg=1996-03-12 00:00:00.0Check 4
3382 [main] DEBUG org.hibernate.SQL - select distinct house0_.ID as ID1_1_, house0_.FK_K_LSK as FK_K_LSK2_1_, house0_.FK_STREET as FK_STREET3_1_ from AR.HOUSE house0_ left outer join AR.KW kw1_ on (house0_.ID=kw1_.FK_HOUSE)left outer join AR.KART kart2_ on (kw1_.ID=kart2_.FK_KW)left outer join PS.REG reg3_ on (kart2_.LSK=reg3_.LSK)left outer join PS.REG_STATE regstate4_ on (kart2_.LSK=regstate4_.LSK) where house0_.FK_K_LSK=187804
在 "Check 1" 点,我看到 SQL 有连接,这很好,
但为什么在 "Check 3" 点我看到奇怪的 SQLs,又击中了基地?
我在 "Check 1" 处使用 "left join fetch" 强制休眠加载所有 childs,
但为什么它需要再次从数据库中检索 childs?
请帮助我,我是否需要更改获取 child 实体的方法?
可能是我必须解决的 Hibernate N+1 问题?
是的,您遇到了 "N+1" select
问题。
为避免 N+1 select
问题,只需确保您加入获取与房屋实体相关的所有关联,尤其是一对一关联。
另外,HQL 应该按照下面示例所示的方式编写,
SELECT employee FROM Employee employee LEFT JOIN FETCH employee.employer
请阅读下面的 HQL 文档:
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html#queryhql-from
我有下一个服务:
public void checkAll() {
Session sess = (Session) em.getDelegate();
System.out.println("Check 1");
Query query = sess.createQuery("select distinct t from House t left join fetch Kw k on t.id=k.fkHouse "
+ "left join fetch Kart a on k.id=a.fkKw "
+ "left join fetch Reg r on a.lsk=r.lsk "
+ "left join fetch RegState s on a.lsk=s.lsk "
+ " "
+ "where t.klsk = 187804");
System.out.println("Check 2");
List<House> lst =query.list();
for (House o : lst) {
System.out.println("Check 3");
for (Kw kw : o.getKw()) {
for (Kart kart : kw.getLsk()) {
for (Reg reg : kart.getReg()) {
System.out.print("Reg="+reg.getDtReg());
break;
}
break;
}
break;
}
break;
}
System.out.println("Check 4");
}
我已经打开 SQL Hibernate 的调试,接下来请看:
Check 1
2393 [main] INFO org.hibernate.hql.internal.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
Check 2
2547 [main] DEBUG org.hibernate.SQL - select distinct house0_.ID as ID1_1_, house0_.FK_K_LSK as FK_K_LSK2_1_, house0_.FK_STREET as FK_STREET3_1_ from AR.HOUSE house0_ left outer join AR.KW kw1_ on (house0_.ID=kw1_.FK_HOUSE)left outer join AR.KART kart2_ on (kw1_.ID=kart2_.FK_KW)left outer join PS.REG reg3_ on (kart2_.LSK=reg3_.LSK)left outer join PS.REG_STATE regstate4_ on (kart2_.LSK=regstate4_.LSK) where house0_.FK_K_LSK=187804
Check 3
2609 [main] DEBUG org.hibernate.SQL - select kw0_.FK_HOUSE as FK_HOUSE3_3_0_, kw0_.ID as ID1_3_0_, kw0_.ID as ID1_3_1_, kw0_.FK_K_LSK as FK_K_LSK2_3_1_, kw0_.FK_HOUSE as FK_HOUSE3_3_1_ from AR.KW kw0_ where kw0_.FK_HOUSE=?
2655 [main] DEBUG org.hibernate.SQL - select kart0_.FK_KW as FK_KW4_2_0_, kart0_.LSK as LSK1_2_0_, kart0_.LSK as LSK1_2_1_, kart0_.FK_K_LSK as FK_K_LSK2_2_1_, kart0_.FIO as FIO3_2_1_, kart0_.FK_KW as FK_KW4_2_1_ from AR.KART kart0_ where kart0_.FK_KW=?
2657 [main] DEBUG org.hibernate.SQL - select reg0_.LSK as LSK6_15_0_, reg0_.ID as ID1_15_0_, reg0_.ID as ID1_15_1_, reg0_.DT_REG as DT_REG2_15_1_, reg0_.DT_REG_TS as DT_REG_TS3_15_1_, reg0_.DT_UNREG as DT_UNREG4_15_1_, reg0_.DT_UNREG_TS as DT_UNREG_TS5_15_1_, reg0_.LSK as LSK6_15_1_, reg0_.FK_PERS as FK_PERS7_15_1_, reg0_.FK_REG_STATUS as FK_REG_STATUS8_15_1_, reg0_.FK_REG_TP as FK_REG_TP9_15_1_ from PS.REG reg0_ where reg0_.LSK=?
Reg=1996-03-12 00:00:00.0Check 4
3382 [main] DEBUG org.hibernate.SQL - select distinct house0_.ID as ID1_1_, house0_.FK_K_LSK as FK_K_LSK2_1_, house0_.FK_STREET as FK_STREET3_1_ from AR.HOUSE house0_ left outer join AR.KW kw1_ on (house0_.ID=kw1_.FK_HOUSE)left outer join AR.KART kart2_ on (kw1_.ID=kart2_.FK_KW)left outer join PS.REG reg3_ on (kart2_.LSK=reg3_.LSK)left outer join PS.REG_STATE regstate4_ on (kart2_.LSK=regstate4_.LSK) where house0_.FK_K_LSK=187804
在 "Check 1" 点,我看到 SQL 有连接,这很好, 但为什么在 "Check 3" 点我看到奇怪的 SQLs,又击中了基地?
我在 "Check 1" 处使用 "left join fetch" 强制休眠加载所有 childs, 但为什么它需要再次从数据库中检索 childs?
请帮助我,我是否需要更改获取 child 实体的方法? 可能是我必须解决的 Hibernate N+1 问题?
是的,您遇到了 "N+1" select
问题。
为避免 N+1 select
问题,只需确保您加入获取与房屋实体相关的所有关联,尤其是一对一关联。
另外,HQL 应该按照下面示例所示的方式编写,
SELECT employee FROM Employee employee LEFT JOIN FETCH employee.employer
请阅读下面的 HQL 文档:
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html#queryhql-from