一级缓存中的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: select person_.id as id0_0_, person_.name as name0_0_, person_.address as person_0_, person_.qq as qq0_0_, contactper0_.groupId as person_0_ from t_person person_ where person_.id=?
小龙哥
Hibernate: select person_.id as id0_0_, person_.name as name0_0_, person_.address as address0_0_, person_.qq as qq0_0_, person_.groupId as groupId0_0_ from t_person person_ where person_.id=?
小马哥
Hibernate: select person_.id as id0_0_, person_.name as name0_0_, person_.address as address0_0_, person_.qq as qq0_0_, person_.groupId as groupId0_0_ from t_person person_ where person_.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]);
}
分享到:
相关推荐
目录 课程内容 1 HelloWorld 2 Hibernate原理模拟 - 什么是O/R Mapping以及为什么... 4 一级缓存和二级缓存和査询缓存(面试题)(详见hibernate_3000_Hibernate_3KindsOf_Cache) 5 事务并发处理(面试的意义更大)
Hibernate处理1-N关系时保存技巧、Hibernate缓存机制、Hibernate批量处理数据、Hibernate三种继承映射策略、hibernate映射体系、Hibernate主键生成策略、持久层DAO设计建议、基于xml文件的bean、使用HibernateAPI在...
内容涵盖安装 Hibernatetools 插件、Session 核心方法、持久化对象生命周期、对象关系映射(1-n、1-1、n-n、继承映射)、检索策略、检索方式(对象导航图、OID 检索、HQL、QBC、本地SQL)、Hibernate 一\二级缓存、...
a) 不在一级缓存之中 b) 数据库可能有记录和它对应,也可能没有记录和它对应 c) 从一个持久态对象转化过来的,从session的一级缓存中出来的,因为调用了session的一些方法,产生了这种对象(session.close()) ...
内容涵盖安装 Hibernatetools 插件、Session 核心方法、持久化对象生命周期、对象关系映射(1-n、1-1、n-n、继承映射)、检索策略、检索方式(对象导航图、OID 检索、HQL、QBC、本地SQL)、Hibernate 一二级缓存、...
3.hibernate的一级缓存 4.介于Connection和Transaction之间的一个对象 5.hibernate中用来做持久化操作的 SessionFactory 1.重量级的,创建和销毁需要消耗很大的资源,不建议频繁创建和销毁 2.线程安全的,一个...
5.8.4 hibernate二级缓存的并发访问策略 333 5.8.5 hibernate的二级缓存配置 334 5.9 hibernate应用的性能优化 336 5.10 多数据源的应用 338 5.11 jdbc的应用 343 5.12 hibernate调用存储过程 343 5.13 xml...
SSH 为 Struts+Spring+Hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架。其中使用Struts作为系统的整体基础架构,负责MVC的分离,在Struts框架的模型部分,控制业务跳转,利用Hibernate框架对持久...
1. 第一个NHibernate应用程序 1.1. 开始NHibernate之旅 1.2. 第一个持久化类 1.3. 映射cat 1.4. 与Cat同乐 1.5. 总结 2. 体系结构(Architecture) 2.1. 概况(Overview) 2.2. 实例状态 2.3. 上下文相关的...
6.2.3 避免N+1查询问题 105 6.3 继承 107 6.4 其他用途 109 6.4.1 使用语句类型和DDL 109 6.4.2 处理超大型数据集 109 6.5 小结 115 第7章 事务 116 7.1 事务是什么 116 7.1.1 一个简单的银行转账示例 116 7.1.2 ...
<...如果只使用中心缓存,只能减小数据库的压力,对于网络带宽的压力,还是有的,速度上也远远逊于本地缓存的效果,所以要结合本地缓存+中心缓存的策略方案,即提高速度,避免群集复制时的瓶颈。