深入理解Hibernate中Iterate方法
一、数据准备(参考前面一篇博文)
数据准备参考博文(这是链接)
在实际需求中有时需要对一些业务数据进行频繁的查询处理,可能会这样处理:
二、list查询剖析
public void testQuerySingleTable_HQL_List() {
Session session = HbnUtils.getSession();
try {
session.beginTransaction();
String hql = "from Student where age > 17";
// 执行第一次查操作
List<Student> list = session.createQuery(hql).list();
for (Student stu : list) {
System.out.println(stu);
}
System.out.println("\t-------第一次查询与第二次查询的分割线--------");
// 执行第二次查操作
List<Student> list_1 = session.createQuery(hql).list();
for (Student stu : list) {
System.out.println(stu);
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
下面是控制台打印的SQL语句和提示语句
Hibernate:
select
student0_.t_id as t_id1_0_,
student0_.t_name as t_name2_0_,
student0_.t_age as t_age3_0_,
student0_.t_score as t_score4_0_
from
t_student student0_
where
student0_.t_age>17
Student [id=8, name=张8三, age=18, score=88.0]
Student [id=9, name=张9三, age=19, score=89.0]
Student [id=10, name=张10三, age=20, score=90.0]
-------第一次查询与第二次查询的分割线--------
Hibernate:
select
student0_.t_id as t_id1_0_,
student0_.t_name as t_name2_0_,
student0_.t_age as t_age3_0_,
student0_.t_score as t_score4_0_
from
t_student student0_
where
student0_.t_age>17
Student [id=8, name=张8三, age=18, score=88.0]
Student [id=9, name=张9三, age=19, score=89.0]
Student [id=10, name=张10三, age=20, score=90.0]
从上面的输出信息可以看出,用List方法Hibernate查询了几次就访问了几次数据库,为了提高效率,本应该在第二次查询的时候可以从缓存中获取,因为第一次的结果已经保存在Session缓存中了!
三、iterate查询剖析
代码
/**
* iterate
* */
@Test
public void testQuerySingleTable_HQL_Iterate() {
Session session = HbnUtils.getSession();
try {
session.beginTransaction();
String hql = "from Student where age>17";
// 执行(第一次查询)
Iterator<Student> iterator = session.createQuery(hql).iterate();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("\t-------第一次查询与第二次查询的分割线--------");
//执行第二次查询操作
List<Student> list_1 = (List<Student>) session.createQuery(hql).iterate();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
执行后控制台输出信息
Hibernate:
select
student0_.t_id as col_0_0_
from
t_student student0_
where
student0_.t_age>17
Hibernate:
select
student0_.t_id as t_id1_0_0_,
student0_.t_name as t_name2_0_0_,
student0_.t_age as t_age3_0_0_,
student0_.t_score as t_score4_0_0_
from
t_student student0_
where
student0_.t_id=?
Student [id=8, name=张8三, age=18, score=88.0]
Hibernate:
select
student0_.t_id as t_id1_0_0_,
student0_.t_name as t_name2_0_0_,
student0_.t_age as t_age3_0_0_,
student0_.t_score as t_score4_0_0_
from
t_student student0_
where
student0_.t_id=?
Student [id=9, name=张9三, age=19, score=89.0]
Hibernate:
select
student0_.t_id as t_id1_0_0_,
student0_.t_name as t_name2_0_0_,
student0_.t_age as t_age3_0_0_,
student0_.t_score as t_score4_0_0_
from
t_student student0_
where
student0_.t_id=?
Student [id=10, name=张10三, age=20, score=90.0]
-------第一次查询与第二次查询的分割线--------
Hibernate:
select
student0_.t_id as col_0_0_
from
t_student student0_
where
student0_.t_age>17
分析输出信息可以看出:Hibernate的iterate执行过程
1):
Hibernate:
select
student0_.t_id as col_0_0_
from
t_student student0_
where
student0_.t_age>17
Student [id=8, name=张8三, age=18, score=88.0]
Student [id=9, name=张9三, age=19, score=89.0]
Student [id=10, name=张10三, age=20, score=90.0]
1):先把所有满足条件的记录的id从数据库查询出来
2):然后根据查询出来的id逐个去查询每一条记录的详细信息
3):先根据id在Session缓存中查找
4):如果没有,就需要去数据库查找,有几个满足条件的id,就需要访问几次数据库
3):当进行第二次查询时,先到数据库进行了一次主键查询,查查满足条件的id,然后直接根据id从Session缓存中读出满足条件的记录的详细信息
四、Query接口的List方法与Iterate方法比较
List方法不会从Session缓存中读取数据
Iterate方法会从Session缓存中读取数据
List方法第一次查询效率高
Iterate方法第一次查询效率很低(2n+1次)
所以为了避免n+1问题,我们取长补短,第一次查询用List,第二次查询用Iterate
五、Query接口的List方法与Iterate方法结合
public void testQuerySingleTable_HQL_IterateAndList() {
Session session = HbnUtils.getSession();
try {
session.beginTransaction();
String hql = "from Student where age>17";
// 执行(第一次查询)
List<Student> list = session.createQuery(hql).list();
for (Student stu : list) {
System.out.println(stu);
}
System.out.println("\t-------第一次查询与第二次查询的分割线--------");
//执行第二次查询操作
Iterator<Student> iterator_1 = session.createQuery(hql).iterate();
while(iterator_1.hasNext()){
System.out.println(iterator_1.next());
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
看结果:———
Hibernate:
select
student0_.t_id as t_id1_0_,
student0_.t_name as t_name2_0_,
student0_.t_age as t_age3_0_,
student0_.t_score as t_score4_0_
from
t_student student0_
where
student0_.t_age>17
Student [id=8, name=张8三, age=18, score=88.0]
Student [id=9, name=张9三, age=19, score=89.0]
Student [id=10, name=张10三, age=20, score=90.0]
-------第一次查询与第二次查询的分割线--------
Hibernate:
select
student0_.t_id as col_0_0_
from
t_student student0_
where
student0_.t_age>17
Student [id=8, name=张8三, age=18, score=88.0]
Student [id=9, name=张9三, age=19, score=89.0]
Student [id=10, name=张10三, age=20, score=90.0]
从结果分析效率确实提高了不少!!!