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的问题。

解决方案有三种:

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

Hibernate的1+N问题的相关文章

Hibernate - HHH000352: Unable to release batch statement

这是hibernate的一个bug,具体看https://hibernate.atlassian.net/browse/HHH-11732?attachmentViewMode=list When using stateless session with jdbc batch size we get an HHH000352: Unable to release batch statement.. error in session.close() after rollback: Code:Con

Hibernate简述及入门实例

一.Hibernate简述 总的概括,Hibernate是一个ORM的轻量级持久层框架,解决了对象和关系数据库中表的不匹配问题(阻抗不匹配)以及拥有开发代码不用去继承hibernate类或接口的优势(无侵入性).hibernate框架实现使得开发人员可以避免反复地编写javajdbc部分代码,应用面向对象的思维操作关系型数据库. 二.使用myeclipse创建hibernate实例两种方法(以hibernate3.5.2及mysql为例) a)手动编写hibernate.cfg.xml及*.hb

对象序列化和反序列--Hibernate的查询和新增极其相似

Hibernate几个关键字持久化,ORM(关系对象映射)(数据库中关系称作是一张表) 应用在项目中,刘一从写的查询代码,每次都挂掉,想要弄出测试数据,自己想着把查询出来的复杂数据弄到文件里自己要是去造那些复杂数据很麻烦public class Object1 { public static void main(String args[]){ HashMap<String, Object> obj=new HashMap<String,Object>(); obj.put(&quo

Hibernate的七种映射关系之七种关联映射(二)

继续上篇博客 七.Hibernate双向一对多关联映射:让多的一端来维护关系. 主要是解决一对多单向关联的缺陷,而不是需求驱动的. 1.在Student.java实体类里添加Classes引用.private Classes classes; 2.Student.hbm.xml里添加many-to-one标签:<many-to-one name="classes" column="classesid"/>.Classes.hbm.xml在例子(六)里的那

Hibernate的七种映射关系之七种关联映射(一)

关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用. 一.Hibernate多对一关联映射:就是在"多"的一端加外键,指向"一"的一端. 比如多个学生对应一个班级,多个用户对应一个级别等等,都是多对一关系. 1."多"端实体加入引用"一"端实体的变量及getter,setter方法. 比如说多个学生对应一个班级,在学生实体类加入:private Grade grade; 2."多"端配置文

mybatis与hibernate的区别

本文转载自:http://blog.csdn.net/wangpeng047/article/details/17038659 以前没怎么用过mybatis,只知道与hibernate一样是个orm数据库框架.随着使用熟练度的增加,发现它与hibernate区别是非常大的,结合至今为止的经验,总结出以下几点: 1. hibernate是全自动,而mybatis是半自动. hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql

hibernate载入持久化对象的两种方式——get、load

一.get与load对照 在hibernate中get和load方法是依据id取得持久化对象的两种方法.但在实际使用的过程中总会把两者混淆,不知道什么情况下使用get好,什么时候使用load方法效率更高.下边具体说一下get和load的不同,有些时候为了对照也会把find加进来. 1.从返回结果上对照: load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常 get方法检索不到的话会返回null 2.从检索运行机制上对照: get方法和fin

org.hibernate.NonUniqueObjectException:a different object with the same identifier value was alread

转自: http://blog.csdn.net/zzzz3621/article/details/9776539 看异常提示意思已经很明显了,是说主键不唯一,在事务的最后执行SQL时,session缓存里面有多个(>1)主键一样的对象. 了解过hibernate的都知道它有一个一级缓存,即session级别的缓存,在一个事务的执行过程中可以管理持久化对象,在事务最后执行SQL,可以减少数据库的操作. 报这个异常就得仔细看看你的代码,一定有地方引用的对象已经不同了. 下面就是一个典型的例子: [

谈谈你对Hibernate的理解

答: 1. 面向对象设计的软件内部运行过程可以理解成就是在不断创建各种新对象.建立对象之间的关系,调用对象的方法来改变各个对象的状态和对象消亡的过程,不管程序运行的过程和操作怎么样,本质上都是要得到一个结果,程序上一个时刻和下一个时刻的运行结果的差异就表现在内存中的对象状态发生了变化. 2.为了在关机和内存空间不够的状况下,保持程序的运行状态,需要将内存中的对象状态保存到持久化设备和从持久化设备中恢复出对象的状态,通常都是保存到关系数据库来保存大量对象信息.从Java程序的运行功能上来讲,保存对

Hibernate session缓存

一级缓存(执行代码时查看console台上的sql语句)  清空缓存 @Test public void demo03(){ //清空缓存 Session session=factory.openSession(); session.beginTransaction(); //1.查询 User user = (User)session.get(User.class, 1); System.out.println(user); //session.evitc(user) //将执行对象从一级缓存