Hibernate的1+N問題

Hibernate 1+N

1+N問題的描述:舉例,一個帖子(Category)含有多個主題(Topic)多個主題(Topic)屬於一個帖子(Category),當只須要查詢Topic時不要查詢Category時,若是 @ManyToOne的屬性fetch=FetchType.EAGER,這時查詢全部Topic時,每查詢一個Topic就會多產生一個SQL語句查詢 相關的Category表的數據,這樣要是有N條Topic數據,就會產生1+N條SQL語句。一樣的在@OneToMany的狀況下,要是在Many方 設置fetch=FetchType.EAGER,一樣也會產生1+N的問題。 java

 

解決方案有三種:mysql

1. fetch=FetchType.LAZY,設爲懶加載sql

2. @BatchSize(size=5)表明一次取5條數據,這樣取5條數據只要發出一條SQL語句,注意是用在被關聯類上的(不建議用)session

3. 迫切左外鏈接檢索 join fetch(Criteria 查詢默認就是join fetchapp

Category類測試

 1 package com.lbx.model;
 2 
 3 import javax.persistence.Entity;
 4 import javax.persistence.GeneratedValue;
 5 import javax.persistence.Id;
 6 
 7 import org.hibernate.annotations.BatchSize;
 8 
 9 @Entity
10 @BatchSize(size=2)
11 public class Category {
12     
13     private int id;
14     private String name;
15     
16     @Id
17     @GeneratedValue
18     public int getId() {
19         return id;
20     }
21     public void setId(int id) {
22         this.id = id;
23     }
24     public String getName() {
25         return name;
26     }
27     public void setName(String name) {
28         this.name = name;
29     }
30     
31 }

Topic類fetch

 1 package com.lbx.model;
 2 
 3 import javax.persistence.Entity;
 4 import javax.persistence.FetchType;
 5 import javax.persistence.GeneratedValue;
 6 import javax.persistence.Id;
 7 import javax.persistence.ManyToOne;
 8 
 9 @Entity
10 public class Topic {
11 
12     private int id;
13     private String title;
14     private Category category;
15     
16     @Id
17     @GeneratedValue
18     public int getId() {
19         return id;
20     }
21     public void setId(int id) {
22         this.id = id;
23     }
24     public String getTitle() {
25         return title;
26     }
27     public void setTitle(String title) {
28         this.title = title;
29     }
30     
31     //@ManyToOne(fetch=FetchType.LAZY)
32     @ManyToOne
33     public Category getCategory() {
34         return category;
35     }
36     public void setCategory(Category category) {
37         this.category = category;
38     }
39     
40 }

hibernate.cfg.xml文件配置ui

 1 <?xml version='1.0' encoding='utf-8'?>
 2 <!DOCTYPE hibernate-configuration PUBLIC
 3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 5 
 6 <hibernate-configuration>
 7 
 8     <session-factory>
 9 
10         <!-- Database connection settings -->
11         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
12         <property name="connection.url">jdbc:mysql://localhost:3306/testhib</property>
13         <property name="connection.username">root</property>
14         <property name="connection.password">root</property>
15 
16         <!-- JDBC connection pool (use the built-in) -->
17        <!-- <property name="connection.pool_size">1</property> --> 
18 
19         <!-- SQL dialect -->
20         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
21 
22         <!-- Enable Hibernate's automatic session context management -->
23         <!-- <property name="current_session_context_class">thread</property>  -->
24 
25         <!-- Echo all executed SQL to stdout -->
26         <property name="show_sql">true</property>
27         <property name="hibernate.format_sql">true</property>
28 
29         <!-- Drop and re-create the database schema on startup -->
30         <property name="hbm2ddl.auto">update</property>
31 
32         <mapping class="com.lbx.model.Category"/>
33         <mapping class="com.lbx.model.Topic"/>
34         <mapping class="com.lbx.model.Msg"/>
35     </session-factory>
36 
37 </hibernate-configuration>

測試代碼this

  1 package com.lbx.model.test;
  2 
  3 import java.util.List;
  4 
  5 import javax.persistence.FetchType;
  6 import javax.persistence.ManyToOne;
  7 
  8 import junit.framework.TestCase;
  9 
 10 import org.hibernate.Query;
 11 import org.hibernate.Session;
 12 import org.hibernate.lucene.Text;
 13 
 14 import com.lbx.hibernate.Util.HibUtil;
 15 import com.lbx.model.Category;
 16 import com.lbx.model.Msg;
 17 import com.lbx.model.Topic;
 18 
 19 public class Test extends TestCase {
 20     
 21     @Text
 22     public void save(){
 23         Session session = HibUtil.getSession();
 24         session.beginTransaction();
 25         
 26         for (int i = 0; i < 3; i++) {
 27             Category c = new Category();
 28             c.setName("c" + i);
 29             Topic t = new Topic();
 30             t.setTitle("t" + i);
 31             t.setCategory(c);
 32             session.save(c);
 33             session.save(t);
 34         }
 35         
 36         session.beginTransaction().commit();
 37         session.close();
 38     }
 39     
 40     //1+N問題(這裏我只要取出Topic就能夠了)
 41     @Text
 42     public void testHQL_01(){
 43         Session session = HibUtil.getSession();
 44         session.beginTransaction();
 45         
 46         //List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
 47         /**
 48          * 這裏要是不把Topic類中不設 @ManyToOne(fetch=FetchType.LAZY),這裏就要發不少SQL語句,關聯的表都會查
 49          * 可是設了@ManyToOne(fetch=FetchType.LAZY) 以後就不會發出查詢相關表的查詢語句,用到的時候才發出
 50          */
 51         Query q = session.createQuery("from Topic");
 52         List<Topic> topics = (List<Topic>)q.list();
 53         System.out.println(topics.size());
 54         for (int i = 0; i < topics.size(); i++) {
 55             System.out.println(topics.get(i).getId() + "  " + topics.get(i).getTitle());
 56         }
 57         session.beginTransaction().commit();
 58         session.close();
 59     }
 60     
 61     //用到被關聯表的信息
 62     @Text
 63     public void testHQL_02(){
 64         Session session = HibUtil.getSession();
 65         session.beginTransaction();
 66         
 67         //List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
 68         /**
 69          * 這裏要是不把Topic類中不設 @ManyToOne(fetch=FetchType.LAZY),這裏就要發不少SQL語句,關聯的表都會查
 70          * 可是設了@ManyToOne(fetch=FetchType.LAZY) 以後就不會發出查詢相關表的查詢語句,用到的時候才發出
 71          */
 72         Query q = session.createQuery("from Topic");
 73         List<Topic> topics = (List<Topic>)q.list();
 74         System.out.println(topics.size());
 75         for (int i = 0; i < topics.size(); i++) {
 76             System.out.println(topics.get(i).getId() + "  " + topics.get(i).getTitle());
 77             /**
 78              * 注意,在這裏要用到Category類的信息,因此就會發出相關的查詢信息
 79              */
 80             System.out.println(topics.get(i).getCategory().getId() + "  " + 
 81                     topics.get(i).getCategory().getName());
 82         }
 83         session.beginTransaction().commit();
 84         session.close();
 85     }
 86     
 87     //@BatchSize的使用,其屬性size=5就表明一次取5個
 88     @Text
 89     public void testHQL_03(){
 90         Session session = HibUtil.getSession();
 91         session.beginTransaction();
 92         
 93         //List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
 94         /**
 95          * 這裏要是不把Topic類中不設 @ManyToOne(fetch=FetchType.LAZY),這裏就要發不少SQL語句,關聯的表都會查
 96          * 可是設了@ManyToOne(fetch=FetchType.LAZY) 以後就不會發出查詢相關表的查詢語句,用到的時候才發出
 97          */
 98         Query q = session.createQuery("from Topic");
 99         List<Topic> topics = (List<Topic>)q.list();
100         System.out.println(topics.size());
101         for (int i = 0; i < topics.size(); i++) {
102             System.out.println(topics.get(i).getId() + "  " + topics.get(i).getTitle());
103             /**
104              * 注意,在這裏要用到Category類的信息,因此就會發出相關的查詢信息
105              */
106             System.out.println(topics.get(i).getCategory().getId() + "  " + 
107                     topics.get(i).getCategory().getName());
108         }
109         session.beginTransaction().commit();
110         session.close();
111     }
112     
113     // join fetch,迫切左外鏈接檢索
114     @Text
115     public void testHQL_04(){
116         Session session = HibUtil.getSession();
117         session.beginTransaction();
118         //Criteria 查詢默認就是join fetch
119         //List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();  
120         /**
121          * 這裏要是不把Topic類中不設 @ManyToOne(fetch=FetchType.LAZY),這裏就要發不少SQL語句,關聯的表都會查
122          * 可是設了@ManyToOne(fetch=FetchType.LAZY) 以後就不會發出查詢相關表的查詢語句,用到的時候才發出
123          */
124         Query q = session.createQuery("from Topic t left join fetch t.category c");
125         List<Topic> topics = (List<Topic>)q.list();
126         System.out.println(topics.size());
127         for (int i = 0; i < topics.size(); i++) {
128             System.out.println(topics.get(i).getId() + "  " + topics.get(i).getTitle());
129         }
130         session.beginTransaction().commit();
131         session.close();
132     }
133     
134 }
相關文章
相關標籤/搜索