hibernate manytoone list 查询 发出的语句为什么是 1+N条

来源:互联网 发布:mac如何导入手机照片 编辑:程序博客网 时间:2024/06/14 07:09

1+N问题的描述:举例,多个主题(Topic)属于一个帖子(Category),一个帖子含有多个主题。当只需要查询Topic时不要查询Category时,如果@ManyToOne的属性fetch=FetchType.EAGER,这时查询所有Topic时,每查询一个Topic就会多产生一个SQL语句查询相关的Category表的数据,这样要是有N条Topic数据,就会产生1+N条SQL语句。同样的在@OneToMany的情况下,要是在Many方设置fetch=FetchType.EAGER,同样也会产生1+N的问题。

 

解决方案有三种:

  1. fetch=FetchType.LAZY,设为懒加载

  2. @BatchSize(size=5)代表一次取5条数据,这样取5条数据只要发出一条SQL语句,注意是用在被关联类上的(不建议用)

  3. 迫切左外连接检索 join fetch(Criteria 查询默认就是join fetch)

下面请看代码:

Category类

Java代码  收藏代码
  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类

Java代码  收藏代码
  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文件配置

Xml代码  收藏代码
  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.           
  36.   
  37.     </session-factory>  
  38.   
  39. </hibernate-configuration>  

 

 

测试代码

Java代码  收藏代码
  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. }  
1 0
原创粉丝点击