歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Hibernate 查詢1+N問題詳解

Hibernate 查詢1+N問題詳解

日期:2017/3/1 10:39:46   编辑:Linux編程

1、1+N簡單來說就是,Person和Phone是一對多關系,現在我看看所有手機的信息,對於其屬於哪個人不感興趣,但把lazy設為false(lazy=false),這樣就會發出1(查詢手機的sql)+N(和所有查詢的這些手機相關的Person的查詢sql),這樣會造成很大的性能開銷。

首先列一下會產生1+N問題的代碼

Person:

[java]
  1. private int id;
  2. private String name;
  3. private int age;
Person.hbm.xml按照常規配置即可

Phone:

[java]
  1. private int id;
  2. private String type;
  3. private String description;
  4. private Person person; //關聯一個用戶
Phone.hbm.xml:

[html]
  1. <hibernate-mapping>
  2. <class name="com.akwolf.n_1.Phone" table="PHONE">
  3. <id name="id" type="int">
  4. <column name="ID" />
  5. <generator class="native" />
  6. </id>
  7. <property name="type" type="java.lang.String">
  8. <column name="TYPE" />
  9. </property>
  10. <property name="description" type="java.lang.String">
  11. <column name="DESCRIPTION" />
  12. </property>
  13. <!-- lazy=false -->
  14. <many-to-one name="person" class="com.akwolf.n_1.Person" fetch="join" lazy="false">
  15. <column name="PERSON_ID" />
  16. </many-to-one>
  17. </class>
  18. </hibernate-mapping>

為了使效果明顯一點,假定一個手機對應一個不同的用戶,現在想數據庫中添加一些數據:

[java]

  1. @Test
  2. public void testSave1() {
  3. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  4. session.beginTransaction();
  5. Person person;
  6. Phone phone;
  7. for (int i = 0; i < 10; i++) {
  8. person = new Person(0, "zhangsan" + i, 21 + i);
  9. phone = new Phone(0, "glay" + i, "Android智能手機", person);
  10. session.save(person);
  11. session.save(phone);
  12. }
  13. session.getTransaction().commit();
  14. }

進行一下下面的查詢會看到,控制台輸出大量的sql

[java]
  1. @Test
  2. public void testQuery1() {
  3. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  4. session.beginTransaction();
  5. List<Phone> list = (List<Phone>) session.createQuery("from Phone")
  6. .list();
  7. for (Phone phone : list) {
  8. System.out.println(phone.getId()); //對關聯的Person並不感興趣
  9. // System.out.println(phone.getId()+"---"+phone.getPerson().getName());
  10. }
  11. session.getTransaction().commit();
  12. }

解決方案

1、還是在Phone.hbm.xml中把對於Person關聯的映射屬性不進行lazy屬性的設置,默認為lazy加載

[html]
  1. <hibernate-mapping>
  2. <class name="com.akwolf.n_1.Phone" table="PHONE">
  3. <id name="id" type="int">
  4. <column name="ID" />
  5. <generator class="native" />
  6. </id>
  7. <property name="type" type="java.lang.String">
  8. <column name="TYPE" />
  9. </property>
  10. <property name="description" type="java.lang.String">
  11. <column name="DESCRIPTION" />
  12. </property>
  13. <!-- lazy=true -->
  14. <many-to-one name="person" class="com.akwolf.n_1.Person" fetch="join">
  15. <column name="PERSON_ID" />
  16. </many-to-one>
  17. </class>
  18. </hibernate-mapping>
2、在lazy=false的情況下,在hql中使用join fetch進行查詢(session.createCriteria就是采用連接查詢的方式),如:

[java]
  1. @Test
  2. public void testQuery2() {
  3. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  4. session.beginTransaction();
  5. List<Phone> list = (List<Phone>) session.createQuery(
  6. "from Phone p left join fetch p.person per").list();
  7. for (Phone phone : list) {
  8. // System.out.println(phone.getId());
  9. System.out.println(phone.getId() + "---"
  10. + phone.getPerson().getName());
  11. }
  12. session.getTransaction().commit();
  13. }
3、對於在Person中設置batch-size應該不算是一種解決方案,對於海量的數據,設置的一些batch-size對於大體來說是無關痛癢的。

ok,這就是小弟看視頻對於1+N問題的一點理解,有理解更為深刻的大蝦不吝賜教。。

Copyright © Linux教程網 All Rights Reserved