Hibernate 1+N 有关问题
Hibernate 1+N 问题1+N问题的描述:举例,多个主题(Topic)属于一个帖子(Category),一个帖子含有多个主题。当
Hibernate 1+N 问题
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的问题。
?
解决方案有三种:
fetch=FetchType.LAZY,设为懒加载@BatchSize(size=5)代表一次取5条数据,这样取5条数据只要发出一条SQL语句,注意是用在被关联类上的(不建议用)迫切左外连接检索 join fetch(Criteria 查询默认就是join fetch)
下面请看代码:Category类?
?
?
package?com.lbx.model.test; ????import?java.util.List; ?? ??import?javax.persistence.FetchType; ?? import?javax.persistence.ManyToOne; ?? ??import?junit.framework.TestCase; ?? ??import?org.hibernate.Query; ?? import?org.hibernate.Session; ?? import?org.hibernate.lucene.Text; ?? ??import?com.lbx.hibernate.Util.HibUtil; ?? import?com.lbx.model.Category; ?? import?com.lbx.model.Msg; ?? import?com.lbx.model.Topic; ?? ??public?class?Test?extends?TestCase?{ ?? ???? ??????@Text?? ????public?void?save(){ ?? ????????Session?session?=?HibUtil.getSession(); ??????????session.beginTransaction(); ?????????? ??????????for?(int?i?=?0;?i?<?3;?i++)?{ ?? ????????????Category?c?=?new?Category(); ?? ????????????c.setName("c"?+?i); ?? ????????????Topic?t?=?new?Topic(); ?? ????????????t.setTitle("t"?+?i); ?? ????????????t.setCategory(c); ??????????????session.save(c); ??????????????session.save(t); ??????????} ?????????? ??????????session.beginTransaction().commit(); ??????????session.close(); ??????} ?????? ??????//1+N问题(这里我只要取出Topic就可以了) ?? ????@Text?? ????public?void?testHQL_01(){ ?? ????????Session?session?=?HibUtil.getSession(); ??????????session.beginTransaction(); ?????????? ??????????//List<Topic>?topics?=?(List<Topic>)session.createCriteria(Topic.class).list(); ?? ????????/** ??????????*?这里要是不把Topic类中不设?@ManyToOne(fetch=FetchType.LAZY),这里就要发很多SQL语句,关联的表都会查 ??????????*?但是设了@ManyToOne(fetch=FetchType.LAZY)?之后就不会发出查询相关表的查询语句,用到的时候才发出 ??????????*/??????????Query?q?=?session.createQuery("from?Topic"); ?? ????????List<Topic>?topics?=?(List<Topic>)q.list(); ??????????System.out.println(topics.size()); ??????????for?(int?i?=?0;?i?<?topics.size();?i++)?{ ?? ????????????System.out.println(topics.get(i).getId()?+?"??"?+?topics.get(i).getTitle()); ?? ????????} ??????????session.beginTransaction().commit(); ??????????session.close(); ??????} ?????? ??????//用到被关联表的信息 ?? ????@Text?? ????public?void?testHQL_02(){ ?? ????????Session?session?=?HibUtil.getSession(); ??????????session.beginTransaction(); ?????????? ??????????//List<Topic>?topics?=?(List<Topic>)session.createCriteria(Topic.class).list(); ?? ????????/** ??????????*?这里要是不把Topic类中不设?@ManyToOne(fetch=FetchType.LAZY),这里就要发很多SQL语句,关联的表都会查 ??????????*?但是设了@ManyToOne(fetch=FetchType.LAZY)?之后就不会发出查询相关表的查询语句,用到的时候才发出 ??????????*/??????????Query?q?=?session.createQuery("from?Topic"); ?? ????????List<Topic>?topics?=?(List<Topic>)q.list(); ??????????System.out.println(topics.size()); ??????????for?(int?i?=?0;?i?<?topics.size();?i++)?{ ?? ????????????System.out.println(topics.get(i).getId()?+?"??"?+?topics.get(i).getTitle()); ?? ????????????/** ??????????????*?注意,在这里要用到Category类的信息,所以就会发出相关的查询信息 ??????????????*/??????????????System.out.println(topics.get(i).getCategory().getId()?+?"??"?+? ?? ????????????????????topics.get(i).getCategory().getName()); ??????????} ??????????session.beginTransaction().commit(); ??????????session.close(); ??????} ?????? ??????//@BatchSize的使用,其属性size=5就代表一次取5个 ?? ????@Text?? ????public?void?testHQL_03(){ ?? ????????Session?session?=?HibUtil.getSession(); ??????????session.beginTransaction(); ?????????? ??????????//List<Topic>?topics?=?(List<Topic>)session.createCriteria(Topic.class).list(); ?? ????????/** ??????????*?这里要是不把Topic类中不设?@ManyToOne(fetch=FetchType.LAZY),这里就要发很多SQL语句,关联的表都会查 ??????????*?但是设了@ManyToOne(fetch=FetchType.LAZY)?之后就不会发出查询相关表的查询语句,用到的时候才发出 ??????????*/??????????Query?q?=?session.createQuery("from?Topic"); ?? ????????List<Topic>?topics?=?(List<Topic>)q.list(); ??????????System.out.println(topics.size()); ??????????for?(int?i?=?0;?i?<?topics.size();?i++)?{ ?? ????????????System.out.println(topics.get(i).getId()?+?"??"?+?topics.get(i).getTitle()); ?? ????????????/** ??????????????*?注意,在这里要用到Category类的信息,所以就会发出相关的查询信息 ??????????????*/??????????????System.out.println(topics.get(i).getCategory().getId()?+?"??"?+? ?? ????????????????????topics.get(i).getCategory().getName()); ??????????} ??????????session.beginTransaction().commit(); ??????????session.close(); ??????} ?????? ??????//?join?fetch,迫切左外连接检索 ?? ????@Text?? ????public?void?testHQL_04(){ ?? ????????Session?session?=?HibUtil.getSession(); ??????????session.beginTransaction(); ??????????//Criteria?查询默认就是join?fetch ?? ????????//List<Topic>?topics?=?(List<Topic>)session.createCriteria(Topic.class).list();?? ?? ????????/** ??????????*?这里要是不把Topic类中不设?@ManyToOne(fetch=FetchType.LAZY),这里就要发很多SQL语句,关联的表都会查 ??????????*?但是设了@ManyToOne(fetch=FetchType.LAZY)?之后就不会发出查询相关表的查询语句,用到的时候才发出 ??????????*/??????????Query?q?=?session.createQuery("from?Topic?t?left?join?fetch?t.category?c"); ?? ????????List<Topic>?topics?=?(List<Topic>)q.list(); ??????????System.out.println(topics.size()); ??????????for?(int?i?=?0;?i?<?topics.size();?i++)?{ ?? ????????????System.out.println(topics.get(i).getId()?+?"??"?+?topics.get(i).getTitle()); ?? ????????} ??????????session.beginTransaction().commit(); ??????????session.close(); ??????} ?????? ??}?