用Hibernate分页的时候,当sort的字段里的值基本相等时候,分页的结果会出现数据重复和丢失。
比如没有分页之前顺序是,1,2,3,4,5,6,7,8,9.(其实按照sort字段排序的话,这些数据顺序基本是一样的,就是大部分是不分顺序的。)
分页后就会出现:第一页(1,2,4,),第二页(3,2,5),第三页(7,8,9),其中2重复了,而6丢失了。仔细分析代码后,发现错误在Query的setFirstResult,setMaxResults里。
代码如下:
       Query query = entityManager.get().createQuery(q.toString());
        for (String key : params.keySet()) {
            query.setParameter(key, params.get(key));
        }
       List queryListA = query.getResultList(); //此语句用来测试,查出来的结果和数据库里吻合。
 
           query.setFirstResult(first);
           query.setMaxResults(count);        List queryListB = query.getResultList(); //此语句用来测试,当执行了setFirstResult,setMaxResults语句后,问题就会出现。如果sort字段是能够按照一定顺序排序的话,分页没有问题,但是如果sort字段值基本相等,则就会出错。
例如:假设没有分页之前,queryListA里得到的值顺序:1,2,3,4,5,6,7,8,9,10。,那么在执行setFirstResult(0),setMaxResults(4)后,queryListB得到的值:2,1,4,3;而并不是1,2,3,4(随着数据库值不同,得到的结果也不一样)也就是说,setFirstResult(first);setMaxResults(count);后,并不是按照查询出来的结果顺序,从first开始取到count的数据的。实在不知道为什么,请高手指教。
非常感谢。

解决方案 »

  1.   

    附加整个查询函数代码:    private Query getQueryByHql(String hql, Map<String, Object> params, int first, int count, LinkedHashMap<String, Boolean> orderMap) {
            boolean isFirstClause;
            StringBuffer q = new StringBuffer(hql);
            if (orderMap != null) {
                isFirstClause = true;
                for (Map.Entry<String, Boolean> entry : orderMap.entrySet()) {
                    if (isFirstClause) {
                        q.append(" order by ");
                    } else {
                        q.append(" , ");
                    }
                    if (entry.getValue()) {
                        q.append("obj.").append(entry.getKey()).append(" asc ");
                    } else {
                        q.append("obj.").append(entry.getKey()).append(" desc ");
                    }
                    isFirstClause = false;
                }
            }
            Query query = entityManager.get().createQuery(q.toString());
            for (String key : params.keySet()) {
                query.setParameter(key, params.get(key));
            }
            if (count > 0 && first >= 0) {
                query.setFirstResult(first);
                query.setMaxResults(count);
            }
            return query;
        }请教高手,万分感谢。
      

  2.   

    很简单for (String key : params.keySet()) 
    set是无序的,所以你那样肯定就是不按照顺序了
      

  3.   

    建议不要把你的数据放到set里面
      

  4.   

    for (String key : params.keySet()) { 这里不是将数据放到set里的,是将sort的字段放到qury里的。查询的数据是放到list里的。
    每次查询的顺序都是一样的,但是在    
    query.setFirstResult(first); 
    query.setMaxResults(count); 
    以后,取出来的数据顺序就不一样了。但是如果sort的字段值是有序的话,顺序还是一样的。
      

  5.   

    if (orderMap != null) { 
                isFirstClause = true; 
                for (Map.Entry <String, Boolean> entry : orderMap.entrySet()) { 
                    if (isFirstClause) { 
                        q.append(" order by "); 
                    } else { 
                        q.append(" , "); 
                    } 
                    if (entry.getValue()) { 
                        q.append("obj.").append(entry.getKey()).append(" asc "); 
                    } else { 
                        q.append("obj.").append(entry.getKey()).append(" desc "); 
                    } 
                    isFirstClause = false; 
                } 
            } orderMap != null就是说不是每次都有order by 了
    每次排序不一样取的当然不一样。
    打印show_sql到后台看看就能明白
      

  6.   

    sql每次都是一样的。
    程序执行到下面这一句的时候,返回的query结果还是一样的。
    Query query = entityManager.get().createQuery(q.toString()); 从setFirstResult(first);setMaxResults(count);执行后,结果就不一样了。难道是说,执行完setFirstResult(first);setMaxResults(count);这个语句后,
    后面又执行了一次sql查询???
    并不是将查询出来的结果,直接从first开始取count条??
      

  7.   

    我觉得既然是分页,用不用first和count应该是统一的,如果first<0,也可以设置first=0
    不管到第几页语句应该统一
      

  8.   

    建议不要把你的数据放到set里面\----------------------------\应该放在哪里?怎么实现呢?
      

  9.   

    在set标签上设置order-by属性试试!<set   order-by="数据库中的某个字段">
    </set>
      

  10.   

    在set标签上设置order-by属性试试! <set  order-by="数据库中的某个字段 asc或者desc"> 
    </set>
      

  11.   

    正解!
    或者直接在hql中写order by 语句,注意order by的内容要非空
      

  12.   

     List queryListB = query.getResultList().setFirstResult(first).setMaxResults(count).list();
      

  13.   

    解决的办法就象14楼说的那样order by一下,注意order by排序字段里的值要有一个字段的值不重复
      

  14.   

    set 是无序的,想要让集合里的值是有序的,最好用TreeMap,键用int类型,这样子取出来的值才会是有序的....