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的问题。
解决方案有三种:
1. fetch=FetchType.LAZY,设为懒加载
2. @BatchSize(size=5)代表一次取5条数据,这样取5条数据只要发出一条SQL语句,注意是用在被关联类上的(不建议用)
3. 迫切左外连接检索 join fetch(Criteria 查询默认就是join fetch
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类
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文件配置
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>
测试代码
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 }
时间: 2024-10-26 03:51:24