Hibernate 1+N问题的原理与解决


什么时候会遇到1+N的问题?


前提:Hibernate默认表与表的关联方法是fetch="select",不是fetch="join",这都是为了懒加载而准备的。

 

1)一对多(<set><list>) ,在1的这方,通过1条sql查找得到了1个对象,由于关联的存在 ,那么又需要将这个对象关联的集合取出,所以合集数量是n还要发出n条sql,于是本来的1条sql查询变成了1 +n条 。

 

2)多对一<many-to-one>  ,在多的这方,通过1条sql查询得到了n个对象,由于关联的存在,也会将这n个对象对应的1 方的对象取出, 于是本来的1条sql查询变成了1 +n条 。

 

3)iterator 查询时,一定先去缓存中找(1条sql查集合,只查出ID),在没命中时,会再按ID到库中逐一查找, 产生1+n条SQL

 

 

怎么解决1+N 问题?


1 )lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。

 

2)使用二级缓存, 二级缓存的应用将不怕1+N 问题,因为即使第一次查询很慢(未命中),以后查询直接缓存命中也是很快的。刚好又利用了1+N 。

 

3) 当然你也可以设定fetch="join",一次关联表全查出来,但失去了懒加载的特性。

【以上内容为转载,如果侵犯了你的权益请及时与我联系】

====================  蟀锅分界线 =========================


给出一个 1+N问题的代码,大家可以去调试一下,看看sql的输出效果

public class HibernateTest {

	public static void main(String[] args) {

		//产生1+N问题
		query();
		//统计总数
		getTotal();
	}
	
	//由于iterator()的缓存特性
	//先从category表中读取idList,然后到二级缓存中
	//如果二级缓存中不存在,则分别得idList中发出n条sql到数据库中查询
	public static void query()
	{
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction tx = session.getTransaction();
		tx.begin();
		
		Query query = session.createQuery(" from Category");
		Iterator<Category> it = query.iterate();
		
		while(it.hasNext())
		{
			Category cat = it.next();
			System.out.println(" name = " + cat.getName() + " , description = "
					+ cat.getDescription());
		}
		
	}
	
	//获取记录总数
	public static void getTotal()
	{
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction tx = session.getTransaction();
		tx.begin();
		
		Query query = session.createQuery(" select count(cat.id) from Category cat ");
		System.out.println(" Category 共有记录数 total = " 
                                         + ((Number)(query.iterate().next())).intValue());
	}
}
 


什么时候会遇到1+N的问题?


前提:Hibernate默认表与表的关联方法是fetch="select",不是fetch="join",这都是为了懒加载而准备的。

 

1)一对多(<set><list>) ,在1的这方,通过1条sql查找得到了1个对象,由于关联的存在 ,那么又需要将这个对象关联的集合取出,所以合集数量是n还要发出n条sql,于是本来的1条sql查询变成了1 +n条 。

 

2)多对一<many-to-one>  ,在多的这方,通过1条sql查询得到了n个对象,由于关联的存在,也会将这n个对象对应的1 方的对象取出, 于是本来的1条sql查询变成了1 +n条 。

 

3)iterator 查询时,一定先去缓存中找(1条sql查集合,只查出ID),在没命中时,会再按ID到库中逐一查找, 产生1+n条SQL

 

 

怎么解决1+N 问题?


1 )lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。

 

2)使用二级缓存, 二级缓存的应用将不怕1+N 问题,因为即使第一次查询很慢(未命中),以后查询直接缓存命中也是很快的。刚好又利用了1+N 。

 

3) 当然你也可以设定fetch="join",一次关联表全查出来,但失去了懒加载的特性。

【以上内容为转载,如果侵犯了你的权益请及时与我联系】

====================  蟀锅分界线 =========================


给出一个 1+N问题的代码,大家可以去调试一下,看看sql的输出效果

public class HibernateTest {

	public static void main(String[] args) {

		//产生1+N问题
		query();
		//统计总数
		getTotal();
	}
	
	//由于iterator()的缓存特性
	//先从category表中读取idList,然后到二级缓存中
	//如果二级缓存中不存在,则分别得idList中发出n条sql到数据库中查询
	public static void query()
	{
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction tx = session.getTransaction();
		tx.begin();
		
		Query query = session.createQuery(" from Category");
		Iterator<Category> it = query.iterate();
		
		while(it.hasNext())
		{
			Category cat = it.next();
			System.out.println(" name = " + cat.getName() + " , description = "
					+ cat.getDescription());
		}
		
	}
	
	//获取记录总数
	public static void getTotal()
	{
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction tx = session.getTransaction();
		tx.begin();
		
		Query query = session.createQuery(" select count(cat.id) from Category cat ");
		System.out.println(" Category 共有记录数 total = " 
                                         + ((Number)(query.iterate().next())).intValue());
	}
}
 

猜你喜欢

转载自paladin1988.iteye.com/blog/1630838
今日推荐