n+1查询不起作用



在下面的代码中,我预计会出现n+1查询问题,但它并没有发生。User.java:

import java.util.*;
public class User {
    private long userId;
    private String firstName;
    private Set phones;
    public User() {
        System.out.println("0-arg constructor :User");
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public long getUserId() {
        return userId;
    }
    public void setUserId(long userId) {
        this.userId = userId;
    }
    public Set getPhones() {
        return phones;
    }
    public void setPhones(Set phones) {
        this.phones = phones;
    }
}

电话号码.java

public class PhoneNumber {
    private String numberType;
    private long phone;
    private long id;
    User parent;
    public PhoneNumber() {
        System.out.println("0-arg constructor :PhoneNumber");
    }
    // write getXxx(),setXxx() methods (4 sets)
    public void setId(long id) {
        this.id = id;
    }
    public long getId() {
        return id;
    }
    public String getNumberType() {
        return numberType;
    }
    public void setNumberType(String numberType) {
        this.numberType = numberType;
    }
    public long getPhone() {
        return phone;
    }
    public void setPhone(long phone) {
        this.phone = phone;
    }
    public void setParent(User parent) {
        this.parent = parent;
    }
    public User getParent() {
        return parent;
    }
}

User.hbm.xml

 <hibernate-mapping>
  <class name="User" 
      table="USER_TABLE" >
      <id name="userId" 
      column="USER_ID"/>
      <property name="firstName"  
       column="FIRST_NAME"/>
     <set name="phones"  
     table="PHONE_NUMBERS" cascade="all"  
       lazy="true">
    <key column="UNID"/>
    <one-to-many 
    class="PhoneNumber"/>
   </set>
  </class>
   </hibernate-mapping>

电话号码.hbm

   <hibernate-mapping>
    <class name="PhoneNumber" table="PHONE_NUMBERS" >
   <id name="phone"  column="PHONE"/>
   <property name="numberType" column="NUMBER_TYPE"/>
   <property name="id" column="UNID" insert="false" update="false"/>
   <many-to-one name="parent" class="User"  column="UNID2" cascade="all"/>
    </class>
    </hibernate-mapping>

hibernate.cfg

    <session-factory>
    <property 
    name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</
     property>
    <property 
   name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</prope
    rty>
    <property 
     name="hibernate.connection.username">system</property>
    <property 
       name="hibernate.connection.password">oracle123</property>
    <property 
    name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="show_sql">true</property>
    <mapping resource="user.hbm.xml"/>          
      <mapping resource="phoneNumber.hbm.xml"/>
</session-factory>

HQLClient.java:

import org.hibernate.*;
import org.hibernate.cfg.*;
import java.util.*;
public class HQLJoinsClient {
    public static void main(String[] args) {
        try {
            Configuration conf = new Configuration().configure();
            SessionFactory factory = conf.buildSessionFactory();
            Session ses = factory.openSession();
            String hql = "from User ";
            Query q = ses.createQuery(hql);
            List l = q.list();
            System.out.println("++++++++++++++++++" + l.size()
                    + "+++++++++++++");
            for (int i = 0; i < l.size(); ++i) {
                User u1 = (User) l.get(i);
                System.out
                        .println("nnnParent----------------------------------------------------------------->");
                System.out.print("user id: " + u1.getUserId());
                System.out.println("FirstName " + u1.getFirstName());
                Set s = u1.getPhones();
                if (s != null) {
                    Iterator it = s.iterator();
                    while (it.hasNext()) {
                        PhoneNumber p1 = (PhoneNumber) it.next();
                        System.out.println("nchild---->");
                        System.out.print("Number Type=" + p1.getNumberType());
                        System.out.print("Phone Number=" + p1.getPhone());
                        System.out.println("User id=" + p1.getId());
                    }// inner while
                }// if
            }
            ses.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出为:

INFO: schema update complete                                                    Hibernate: select user0_.USER_ID as USER1_0_, user0_.FIRST_NAME as FIRST2_0_ from USER_TABLE user0_                                                             

0-arg constructor :User 0-arg constructor :User                                                         0-arg constructor :User                                                         ++++++++++++++++++3+++++++++++++++++++++++++                                                                                                                                                                                                                                                                                    Parent----------------------------------------------------------------->        user id: 102FirstName ravi                                                      Hibernate: select phones0_.UNID as UNID1_, phones0_.PHONE as PHONE1_, phones0_.PHONE as PHONE1_0_, phones0_.NUMBER_TYPE as NUMBER2_1_0_, phones0_.UNID as UNID1_0_, phones0_.UNID2 as UNID4_1_0_ from PHONE_NUMBERS phones0_ where phones0_.UNID=?                                                                              0-arg constructor :PhoneNumber                                                  0-arg constructor :PhoneNumber                                                  0-arg constructor :PhoneNumber                                                                                                                                  child---->                                                                      Number Type=resPhone Number=81818181User id=102                                                                                                                 child---->                                                                      Number Type=officePhone Number=71717171User id=102                                                                                                              child---->                                                                      Number Type=homePhone Number=91919191User id=102                                                                                                                                                                                                                                                                                Parent----------------------------------------------------------------->        user id: 103FirstName jayendra                                                  Hibernate: select phones0_.UNID as UNID1_, phones0_.PHONE as PHONE1_, phones0_.PHONE as PHONE1_0_, phones0_.NUMBER_TYPE as NUMBER2_1_0_, phones0_.UNID as UNID1_0_, phones0_.UNID2 as UNID4_1_0_ from PHONE_NUMBERS phones0_ where phones0_.UNID=?                                                                              0-arg constructor :PhoneNumber                                                  0-arg constructor :PhoneNumber                                                                                                                                  child---->                                                                      Number Type=resPhone Number=3748329382User id=103                                                                                                               child---->                                                                      Number Type=homePhone Number=538432342User id=103                                                                                                                                                                                                                                                                               Parent----------------------------------------------------------------->        user id: 104FirstName mike                                                      Hibernate: select phones0_.UNID as UNID1_, phones0_.PHONE as PHONE1_, phones0_.PHONE as PHONE1_0_, phones0_.NUMBER_TYPE as NUMBER2_1_0_, phones0_.UNID as UNID1_0_, phones0_.UNID2 as UNID4_1_0_ from PHONE_NUMBERS phones0_ where phones0_.UNID=?                                                                              0-arg constructor :PhoneNumber                                                  0-arg constructor :PhoneNumber                                                                                                                                  child---->                                                                      Number Type=homePhone Number=238349384User id=104                                                                                                               child---->                                                                      Number Type=mobilePhone Number=9455682832User id=104                            

我预计每个电话号码记录到一个用户id都会有单独的选择语句,但对于3个电话号码-1个用户id,有一个选择语句[而不是(3+1)]。为什么会这样?

谢谢!

映射中几乎没有问题。

首先,one-to-manymany-to-one在关系数据库中用一列表示。两端都是同一列,所以这是错误的:

// class name="User"
<set name="phones" table="PHONE_NUMBERS"
     cascade="all" lazy="true">
    <key column="UNID"/>                   // this column must be same
    <one-to-many class="PhoneNumber" />
</set>
// class name="PhoneNumber"
...   
<many-to-one name="parent" class="User" 
       column="UNID2"                      // as this column
       cascade="all"/>

两个列值必须针对同一列

其次,您正在经历1+N问题。用户有一个SELECT,但他们的手机有三个选择。这是标准的1+N问题。

解决方案是使用:

20.1.5.使用批量取数

小型报价:

使用批取,如果访问一个代理,Hibernate可以加载几个未初始化的代理。批量获取是对惰性选择获取策略的优化。有两种方法可以配置批处理获取:在类级别和集合级别。

类/实体的批量获取更容易理解。考虑以下示例:在运行时,会话中加载了25个Cat实例,每个Cat都有一个对其所有者Person的引用。Person类用一个代理进行映射,lazy=";真";。如果您现在遍历所有的猫并对每个猫调用getOwner(),那么默认情况下,Hibernate将执行25条SELECT语句来检索代理的所有者。您可以通过在Person:的映射中指定批量大小来调整此行为

<class name="Person" batch-size="10">...</class>

因此,我们应该在收集上使用此设置:

<set name="phones" table="PHONE_NUMBERS" batch-size="25"
     cascade="all" lazy="true">

我建议在每个类映射中也使用它:

<class name="PhoneNumber" table="PHONE_NUMBERS" batch-size="25">