n + 1查询不起作用

时间:2014-09-13 07:32:44

标签: hibernate hibernate-onetomany select-n-plus-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;
    }
}

PhoneNumber.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>

phoneNumber.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("\n\n\nParent----------------------------------------------------------------->");

                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会有单独的select语句,但是对于3个Phonenumber-1 userid,有一个select语句[而不是(3 + 1)]。为什么会这样?

谢谢!

1 个答案:

答案 0 :(得分:0)

您的地图中存在一些问题。

首先,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,但是为他们的电话选择了3个。这是标准的1 + N问题。

解决方案是使用:

20.1.5. Using batch fetching

小引用:

  

使用批量提取,如果访问一个代理,Hibernate可以加载几个未初始化的代理。批量提取是延迟选择提取策略的优化。您可以通过两种方式配置批量提取:在类级别和集合级别。

     

更容易理解批量提取类/实体。请考虑以下示例:在运行时,您在会话中加载了25个Cat实例,并且每个Cat都有一个对其所有者的引用,即Person。 Person类使用代理映射,lazy =&#34; true&#34;。如果您现在遍历所有猫并在每个猫上调用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">