Hibernate缓存策略之1+N(一)

一级缓存中的1+N问题

所谓1+N指的就是:一条查询实体对象的ID列表的查询语句和迭代查询具体的多个实体对象的查询语句

  • session的load/get或iterate操作会利用缓存,如果缓存中已有实体对象,将不再发出查询语句查询实体对象
  • session的list操作将不会利用缓存,每次查询,都会发出查询语句
  • 如果查询实体对象,则list操作直接发查询语句把实体对象加载到内存,而iterate操作先发查询语句查ID列表,再发查询语句根据ID逐个查询实体对象
  • 如果查询的是普通结果集,则list和iterate操作将没有区别

看看下面的代码及描述:

//list()操作,hibernate会马上发出查询语句查询所有的实体对象到内存中!


List persons = 
	session.createQuery("select p from Person p").list();


for (Iterator iterator = persons.iterator(); iterator.hasNext();) {
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}

打印结果是这样的:

Hibernate: select person_.id as id0_, person_.name as name0_, person_.address as address0_, person_.qq as qq0_, person_.groupId as groupId0_ from t_person person_小龙哥

小马哥

神马哥

-----------------------------------------------------------------------------------------

 那么iterate操作呢:

//用iterate操作查询实体对象的时候,首先会发出一条查询语句查询实体对象的ID列表
Iterator iterator = 
	session.createQuery("select p from Person p").iterate();
for (; iterator.hasNext();) {	
//当迭代访问具体的某个实体对象的时候,hibernate再次发出查询语句查询此实体对象的数据!
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}
 

Hibernate: select person_.id as col_0_0_ from t_person person_这个是查询id的语句

以下是查找具体对象的3条语句

Hibernate:selectperson_.idasid0_0_,person_.nameasname0_0_,person_.addressasperson_0_,person_.qqasqq0_0_,contactper0_.groupIdasperson_0_fromt_personperson_whereperson_.id=?

小龙哥

Hibernate:selectperson_.idasid0_0_,person_.nameasname0_0_,person_.addressasaddress0_0_,person_.qqasqq0_0_,person_.groupIdasgroupId0_0_fromt_personperson_whereperson_.id=?

小马哥

Hibernate:selectperson_.idasid0_0_,person_.nameasname0_0_,person_.addressasaddress0_0_,person_.qqasqq0_0_,person_.groupIdasgroupId0_0_fromt_personperson_whereperson_.id=?

神马哥

现在来将他们在同一个session中查找两次看看有什么现象?sql语句就不写了

//list()操作,hibernate会马上发出查询语句查询所有的实体对象到内存中!
List persons = 
	session.createQuery("select p from Person p").list();
for (Iterator iterator = persons.iterator(); iterator.hasNext();) {
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}

//第二次,还是用list操作查询实体对象
//hibernate还会发查询语句查询实体对象
//所以,list操作会把实体对象放入一级缓存,但list操作不利用一级缓存!


persons = session.createQuery("select p from Person p")
	.list();
for (Iterator iterator = persons.iterator(); iterator.hasNext();) {
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}

那么再看看两个iterate操作

//用iterate操作查询实体对象的时候,首先会发出一条查询语句查询实体对象的ID列表
Iterator iterator = session.createQuery("select p from Person p").iterate();
for (; iterator.hasNext();) {
	//当迭代访问具体的某个实体对象的时候,hibernate再次发出查询语句查询此实体对象的数据!
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}
//第二次用iterate操作
//iterate操作只会再发一条查询ID列表的SQL语句,针对这些实体对象访问的时候,不再发出查询语句
//iterate操作除了能够将实体对象放入一级缓存之外,它还会利用一级缓存!!


iterator = session.createQuery("select p from Person p").iterate();
for (; iterator.hasNext();) {
	//不再发出SQL查询语句!
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}

 看到这样的结果,我们是不是可以把这两个操作结合起来提高查询性能呢?其实是可以的,再看看下面的代码

//list()操作,hibernate会马上发出查询语句查询所有的实体对象到内存中!
List persons = 
	session.createQuery("select p from Person p").list();
for (Iterator iterator = persons.iterator(); iterator.hasNext();) {
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}
//下面iterate操作,将只发出一条查询ID列表的SQL语句
Iterator iterator = session.createQuery("select p from Person p").iterate();
for (; iterator.hasNext();) {
	//不再发出SQL语句!
	Person p = (Person) iterator.next();
	System.out.println(p.getName());
}

 显然上面的代码分别利用list和iterate的特性,大大提高了数据查询的性能,如果不是list而是get操作,其实是一样的。

那如果查询的是一些普通结果集呢?所谓普通结果集就是某实体的某些属性,而上面查找的都是实体,看看下面的代码:

//如果查询的不是实体对象,而是一些普通的结果集,则list操作和iterate操作将没有区别
//不管是List还是iterate操作,每次查询,都会发出SQL语句!!!不再利用一级缓存!!

//也就是说,一级缓存中缓存的数据只是实体
对象,而不是一般的普通结果集!

List persons = 
	session.createQuery("select p.id,p.name from Person p").list();
for (Iterator iterator = persons.iterator(); iterator.hasNext();) {
	Object[] p = (Object[]) iterator.next();
	System.out.println(p[0]+","+p[1]);
}
//如果查询的不是实体对象,而是一些普通的结果集,则list操作和iterate操作将没有区别

Iterator iterator = session.createQuery("select p.id,p.name from Person p").iterate();
for (; iterator.hasNext();) {
	Object[] p = (Object[]) iterator.next();
	System.out.println(p[0]+","+p[1]);
}
 

相关推荐