Hibernate : Query.list()、Query.iterator()的区别

来源:互联网 发布:淘宝收藏有礼怎么设置 编辑:程序博客网 时间:2024/05/21 09:09

Query上有list()iterator()方法,两者的差别在于list()方法在读取数据时,并不会利用到快取,而是直接再向数据库查询,而iterator()则将读取到的数据写到快取,并于读取时再次利用。

来看看下面的程序:

Session session =sessionFactory.openSession();
       
 
Query query = session.createQuery("from User");
List users = query.list();
users = query.list();

session.close();


这个程序片段会使用两次SQL来查询数据库:

Hibernate: select user0_.id as id,user0_.name as name0_, user0_.age as age0_ from user user0_
Hibernate: select user0_.id as id, user0_.name as name0_, user0_.age as age0_from user user0_


如果在Session关闭之前,要再将所有数据在取出,可以使用iterator()方法,例如:

Session session =sessionFactory.openSession();

Query query = session.createQuery("from User");
Iterator users = query.iterate();
users = query.iterate();

session.close();


这个程序片段会使用一次SQL向数据库查询,第二次则直接从快取中取得数据:

Hibernate: select user0_.id as col_0_0_from user user0_


由于使用iterator()方法时会使用到Session level快取,所以在查询大量数据时,会耗用大量的内存,必要时可以使用Sessionevict()clear()方法来清除快取。


list只能利用查询缓存(但在交易系统中查询缓存作用不大),无法利用二级缓存中的单个实体,但list查出的对象会写入二级缓存,但它一般只生成较少的执行SQL语句,很多情况就是一条(无关联)。
  ii. iterator则可以利用二级缓存,对于一条查询语句,它会先从数据库中找出所有符合条件的记录的ID,再通过ID去缓存找,对于缓存中没有的记录,再构造语句从数据库中查出,因此很容易知道,如果缓存中没有任何符合条件的记录,使用iterator会产生N+1条SQL语句(N为符合条件的记录数)


ps:List仅仅会填充二级缓存,却不能利用二级缓存,而iterator可以读二级缓存,然而无法命中的话,效率却很低。一个最好的办法就是,第一次查询使用List,随后的查询使用iterator,现在的问题是如何做到第一次查询使用List,随后查询使用iterator。
  先来考察一下缓存的作用:缓存之所以可以命中,前提条件是该数据被使用的非常频繁,同时更新的可能性相当小,如果数据会频繁修改,那么毫无疑问,缓存不会带来任何好处。明确了这一点,我们就明白什么对象应该进行缓存了。显然,对于那些经常会被访问到的小批量的诸如基础信息,用户和权限信息是非常适合进行缓存的,这些数据我们可以在应用启动的时候就执行一次list方法查询,进行缓存填充(例如写一个InitBean类进行数据缓存初始化),此外在数据被修改的时候,再次执行list方法,进行缓存填充。而在使用这些数据的其他地方,统统使用iterator方法。这样就可以实现所谓的第一次查询使用List,随后的查询使用iterator了。