论坛首页 Java企业应用论坛

Hibernate(十五):用Hibernate求记录总数的一个怪胎

浏览 3095 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-07  

     项目中求满足某一条件记录数是这样来的: super.getHibernateTemplate().findByCriteria(d).size(). 有些怪. 由于对接口编程与hibernate也多少有些了解,以学习的心态首先想到的是,可能hibernate方法findByCriteria的是一List 的非ArrayList实现类,也就是hibernate自身的一个特定功能的list实现类, 而再在调用size方法时,那个实现类实际上是执行了类似count(*)那样的SQL.

    有了这样的假想后, 心里老放着也不是个事, 验证下吧. 于是在IDE里设置断点,调用.

    出现了如下图所示的情况:

 

   

    findByCriteria方法返回的results不是什么高级特定功能的list实现类, 也就是平常的ArrayList! 这还了得!从图中也能到, 返回值的size是3008! 下面的值能看到一个一个的Node实例. 这样也就是说, findByCriteria后再size的策略就是把所有满足条件的所有数据库记录转为java对象加载到JVM内存中. 费了这么大的事,又占了这么多的内存空间,就为了看这些记录的个数!

    顺着上面的思路, 再有些夸张地打个比方: 国家为了搞人口普查,也想不到什么好的办法(或者说领导由于某些原因压根就没想),于是一拍脑袋,让全国的人来下数数不就得了. 于是间,火车、汽车、飞机、船等交通工具都塞满了人,他们有一个目的地--首都,也为了一个目标,让国家有关部门数一数人数..... 数完了, 那你们还回去干手里的活吧.

    有些搞笑了.

    凡事都是有些它存在的原因的,顺着这个想法下来: 这种方法有什么好处? 现在能想到的一个就是,findByCriteria后再size的策略提供了一种统一的方法.这样就可以写到父类里,供子类孙类调用,也就是说在代码实现上有优势.

    那有没有可能以效率高的运行方式--也就是很容易想到的count(*)--来做到代码上比较通用的实现呢? 抛砖引玉,希望能得到大家的指点.

  • 大小: 34.8 KB
   发表时间:2009-04-07  
为什么不直接在HQL里用count?
0 请登录后投票
   发表时间:2009-04-08  
估计Hibernate中的list的size()方法压根就不是用来做数据总数汇总的,真正的汇总应当使用HQL或者QBC等查询语句调用相应的汇总函数,交由数据库来实现而不能把计算数据总数的任务交个程序把数据一次性的查出了来,在调用list的size()方法。这么做即使你不使用list的size方法,也是一次性的把数据全部加载到内存中。
所以如果业务上确实需要获得查询的总数,应当使用相应的汇总函数把数据汇总的任务交给DB来解决。
这只是我的个人观点!拍砖
0 请登录后投票
   发表时间:2009-04-08  
为什么要用红色遮起来呢?这个属于商业机密麽
0 请登录后投票
   发表时间:2009-04-08  
yidao620c 写道
为什么要用红色遮起来呢?这个属于商业机密麽


呵呵, 不算什么商业机密,但从那一团红色自能看出我现在的公司以及现在的项目,为了避免可能的麻烦就用红色涂了起来.

麻烦还是少惹些为好啦.
0 请登录后投票
   发表时间:2009-04-08   最后修改:2009-04-08
d.setProjection(Projections.countDistinct("id"));
List list = this.findByCriteria(d);
int result = 0;
for (Iterator it = list.iterator(); it.hasNext();) {
Integer item = (Integer) it.next();
result += item;
}
return result;
1 请登录后投票
   发表时间:2009-04-08  
daquan198163 写道
d.setProjection(Projections.countDistinct("id"));
List list = this.findByCriteria(d);
int result = 0;
for (Iterator it = list.iterator(); it.hasNext();) {
Integer item = (Integer) it.next();
result += item;
}
return result;



谢谢daquan198163, 看你了的解法, 我想通了些: super.getHibernateTemplate().findByCriteria(d)这样的写法是可以得到汇总信息的.

但findByCriteria后list方法还是显的有些不伦不类.

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

前进了一步,  可以基于daquan198163的写法写一通用的求汇总信息的父类方法.
9 请登录后投票
   发表时间:2009-04-08  
wang19841229 写道
Hibernate中的list的size()方法压根就不是用来做数据总数汇总的,真正的汇总应当使用HQL或者QBC等查询语句调用相应的汇总函数,交由数据库来实现而不能把计算数据总数的任务交个程序把数据一次性的查出了来,
正解list的size()方法是List的方法和Hibernate没有关系,当然也可以用它来做数据总数的汇总。
在criteria中做数据总汇一般是
criteria.setProjection(Projections.rowCount());
		return (Integer) hibernateTemplate.execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return criteria.getExecutableCriteria(session).uniqueResult();
			}
		});

注意Projections.rowCount(),代码应该还能再简化
1 请登录后投票
   发表时间:2009-04-08  
确实用list去求size是个很占用空间的问题。
   更青睐count
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics