Hibernate实现分页查询的原理分析

本文详细解析了Hibernate如何实现分页查询的原理,包括其内部机制和关键步骤。通过对示例代码的分析,揭示了Hibernate在处理分页查询时的参数处理和SQL生成过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hibernate 可以实现分页查询,例如:
从第2万条开始取出100条记录

 

代码
  1. Query q = session.createQuery("from Cat as c");   
  2. q.setFirstResult(20000);   
  3. q.setMaxResults(100);   
  4. List l = q.list();  
<script type="text/javascript">render_code();</script>

 

那么Hibernate底层如何实现分页的呢?实际上Hibernate的查询定义在net.sf.hibernate.loader.Loader这个类里面,仔细阅读该类代码,就可以把问题彻底搞清楚。

Hibernate2.0.3的Loader源代码第480行以下:

 

代码
  1. if (useLimit) sql = dialect.getLimitString(sql);           
  2. PreparedStatement st = session.getBatcher().prepareQueryStatement(sql, scrollable);  
<script type="text/javascript">render_code();</script>

 

如果相应的数据库定义了限定查询记录的sql语句,那么直接使用特定数据库的sql语句。

然后来看net.sf.hibernate.dialect.MySQLDialect:

 

代码
  1. public boolean supportsLimit() {   
  2.   return true;   
  3. }   
  4. public String getLimitString(String sql) {   
  5.   StringBuffer pagingSelect = new StringBuffer(100);   
  6.   pagingSelect.append(sql);   
  7.   pagingSelect.append(" limit ?, ?");   
  8.   return pagingSelect.toString();   
  9. }  
<script type="text/javascript">render_code();</script>

 

这是MySQL的专用分页语句,再来看net.sf.hibernate.dialect.Oracle9Dialect:

 

代码
  1. public boolean supportsLimit() {   
  2.   return true;   
  3. }   
  4.   
  5. public String getLimitString(String sql) {   
  6.   StringBuffer pagingSelect = new StringBuffer(100);   
  7.   pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");   
  8.   pagingSelect.append(sql);   
  9.   pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");   
  10.   return pagingSelect.toString();   
  11. }  
<script type="text/javascript">render_code();</script>

 

Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最快的方式,如果只是一层或者两层的查询语句的rownum不能支持order by。

除此之外,Interbase,PostgreSQL,HSQL也支持分页的sql语句,在相应的Dialect里面,大家自行参考。

如果数据库不支持分页的SQL语句,那么根据在配置文件里面
#hibernate.jdbc.use_scrollable_resultset true
默认是true,如果你不指定为false,那么Hibernate会使用JDBC2.0的scrollable result来实现分页,看Loader第430行以下:

 

代码
  1. if ( session.getFactory().useScrollableResultSets() ) {   
  2.   // we can go straight to the first required row   
  3.   rs.absolute(firstRow);   
  4. }   
  5. else {   
  6.   // we need to step through the rows one row at a time (slow)   
  7.   for ( int m=0; m<firstRow; m++ ) rs.next();   
  8. }  
<script type="text/javascript">render_code();</script>

 

如果支持scrollable result,使用ResultSet的absolute方法直接移到查询起点,如果不支持的话,使用循环语句,rs.next一点点的移过去。

可见使用Hibernate,在进行查询分页的操作上,是具有非常大的灵活性,Hibernate会首先尝试用特定数据库的分页sql,如果没用,再尝试Scrollable,如果不行,最后采用rset.next()移动的办法。

在查询分页代码中使用Hibernate的一大好处是,既兼顾了查询分页的性能,同时又保证了代码在不同的数据库之间的可移植性。




声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。
相关文章:    使用JDBC和Hibernate来写入Blob型数据到Oracle中    Hibernate的JNDI绑定分析
评论    共 2 条 发表评论
zhujunli0310     2007-01-13 07:24

首先,我要感谢你提供的帖子。
这里我有一个问题,就是hibernate3以后的版本,对于不同的数据库是如何实现的,我感觉说的不是很清楚。
能不能在详细的说一下。

joachimz     2007-01-13 09:10

 

robbin 写道

 

再来看net.sf.hibernate.dialect.Oracle9Dialect:

 

代码
  1. public boolean supportsLimit() {   
  2.   return true;   
  3. }   
  4.   
  5. public String getLimitString(String sql) {   
  6.   StringBuffer pagingSelect = new StringBuffer(100);   
  7.   pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");   
  8.   pagingSelect.append(sql);   
  9.   pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");   
  10.   return pagingSelect.toString();   
  11. }  
<script type="text/javascript">render_code();</script>

 

Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最快的方式,如果只是一层或者两层的查询语句的rownum不能支持order by。

 

Oracle的这种实现如果有order by子句依然有问题。某些时候会导致翻页有记录重复或者遗失,很难找到规律,非常奇怪。

后来去google了一下,有Oracle专家说需要order by的时候必须带上unique的字段,例如主键或者rowid等。

另外,在使用这种采用rownum的查询时,尽管速度相对比较快,但是后台Oracle在内存和CPU的消耗上会增加许多。其实除非结果集非常庞大(几万以上),并且必须翻倒很后面(skip的记录很多),采用ResultSet.absolute方法性能还可以,并没有数量级上的差别。

Hibernate3提供了DetachedCriteria,使得我们可以在Web层构造detachedCriteria,然后调用业务层Bean,进行动态条件查询,根据这一功能,我设计了通用的抽象Bean基类和分页类支持,代码来自于Quake Wang的javaeye-core包的相应类,然后又做了很多修改。

分页支持类:

 

java 代码
  1. package com.javaeye.common.util;   
  2.   
  3. import java.util.List;   
  4.   
  5. public class PaginationSupport {   
  6.   
  7.     public final static int PAGESIZE = 30;   
  8.   
  9.     private int pageSize = PAGESIZE;   
  10.   
  11.     private List items;   
  12.   
  13.     private int totalCount;   
  14.   
  15.     private int[] indexes = new int[0];   
  16.   
  17.     private int startIndex = 0;   
  18.   
  19.     public PaginationSupport(List items, int totalCount) {   
  20.         setPageSize(PAGESIZE);   
  21.                 setTotalCount(totalCount);   
  22.         setItems(items);           
  23.         setStartIndex(0);   
  24.     }   
  25.   
  26.     public PaginationSupport(List items, int totalCount, int startIndex) {   
  27.                 setPageSize(PAGESIZE);   
  28.         setTotalCount(totalCount);   
  29.         setItems(items);           
  30.         setStartIndex(startIndex);   
  31.     }   
  32.   
  33.     public PaginationSupport(List items, int totalCount, int pageSize, int startIndex) {   
  34.                 setPageSize(pageSize);   
  35.         setTotalCount(totalCount);   
  36.         setItems(items);   
  37.         setStartIndex(startIndex);   
  38.     }   
  39.   
  40.     public List getItems() {   
  41.         return items;   
  42.     }   
  43.   
  44.     public void setItems(List items) {   
  45.         this.items = items;   
  46.     }   
  47.   
  48.     public int getPageSize() {   
  49.         return pageSize;   
  50.     }   
  51.   
  52.     public void setPageSize(int pageSize) {   
  53.         this.pageSize = pageSize;   
  54.     }   
  55.   
  56.     public int getTotalCount() {   
  57.         return totalCount;   
  58.     }   
  59.   
  60.     public void setTotalCount(int totalCount) {   
  61.         if (totalCount > 0) {   
  62.             this.totalCount = totalCount;   
  63.             int count = totalCount / pageSize;   
  64.             if (totalCount % pageSize > 0)   
  65.                 count++;   
  66.             indexes = new int[count];   
  67.             for (int i = 0; i < count; i++) {   
  68.                 indexes[i] = pageSize * i;   
  69.             }   
  70.         } else {   
  71.             this.totalCount = 0;   
  72.         }   
  73.     }   
  74.   
  75.     public int[] getIndexes() {   
  76.         return indexes;   
  77.     }   
  78.   
  79.     public void setIndexes(int[] indexes) {   
  80.         this.indexes = indexes;   
  81.     }   
  82.   
  83.     public int getStartIndex() {   
  84.         return startIndex;   
  85.     }   
  86.   
  87.     public void setStartIndex(int startIndex) {   
  88.         if (totalCount <= 0)   
  89.             this.startIndex = 0;   
  90.         else if (startIndex >= totalCount)   
  91.             this.startIndex = indexes[indexes.length - 1];   
  92.         else if (startIndex < 0)   
  93.             this.startIndex = 0;   
  94.         else {   
  95.             this.startIndex = indexes[startIndex / pageSize];   
  96.         }   
  97.     }   
  98.   
  99.     public int getNextIndex() {   
  100.         int nextIndex = getStartIndex() + pageSize;   
  101.         if (nextIndex >= totalCount)   
  102.             return getStartIndex();   
  103.         else  
  104.             return nextIndex;   
  105.     }   
  106.   
  107.     public int getPreviousIndex() {   
  108.         int previousIndex = getStartIndex() - pageSize;   
  109.         if (previousIndex < 0)   
  110.             return 0;   
  111.         else  
  112.             return previousIndex;   
  113.     }   
  114.   
  115. }  
<script type="text/javascript">render_code();</script>

 

抽象业务类

java 代码
  1. /**  
  2.  * Created on 2005-7-12  
  3.  */  
  4. package com.javaeye.common.business;   
  5.   
  6. import java.io.Serializable;   
  7. import java.util.List;   
  8.   
  9. import org.hibernate.Criteria;   
  10. import org.hibernate.HibernateException;   
  11. import org.hibernate.Session;   
  12. import org.hibernate.criterion.DetachedCriteria;   
  13. import org.hibernate.criterion.Projections;   
  14. import org.springframework.orm.hibernate3.HibernateCallback;   
  15. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;   
  16.   
  17. import com.javaeye.common.util.PaginationSupport;   
  18.   
  19. public abstract class AbstractManager extends HibernateDaoSupport {   
  20.   
  21.     private boolean cacheQueries = false;   
  22.   
  23.     private String queryCacheRegion;   
  24.   
  25.     public void setCacheQueries(boolean cacheQueries) {   
  26.         this.cacheQueries = cacheQueries;   
  27.     }   
  28.   
  29.     public void setQueryCacheRegion(String queryCacheRegion) {   
  30.         this.queryCacheRegion = queryCacheRegion;   
  31.     }   
  32.   
  33.     public void save(final Object entity) {   
  34.         getHibernateTemplate().save(entity);   
  35.     }   
  36.   
  37.     public void persist(final Object entity) {   
  38.         getHibernateTemplate().save(entity);   
  39.     }   
  40.   
  41.     public void update(final Object entity) {   
  42.         getHibernateTemplate().update(entity);   
  43.     }   
  44.   
  45.     public void delete(final Object entity) {   
  46.         getHibernateTemplate().delete(entity);   
  47.     }   
  48.   
  49.     public Object load(final Class entity, final Serializable id) {   
  50.         return getHibernateTemplate().load(entity, id);   
  51.     }   
  52.   
  53.     public Object get(final Class entity, final Serializable id) {   
  54.         return getHibernateTemplate().get(entity, id);   
  55.     }   
  56.   
  57.     public List findAll(final Class entity) {   
  58.         return getHibernateTemplate().find("from " + entity.getName());   
  59.     }   
  60.   
  61.     public List findByNamedQuery(final String namedQuery) {   
  62.         return getHibernateTemplate().findByNamedQuery(namedQuery);   
  63.     }   
  64.   
  65.     public List findByNamedQuery(final String query, final Object parameter) {   
  66.         return getHibernateTemplate().findByNamedQuery(query, parameter);   
  67.     }   
  68.   
  69.     public List findByNamedQuery(final String query, final Object[] parameters) {   
  70.         return getHibernateTemplate().findByNamedQuery(query, parameters);   
  71.     }   
  72.   
  73.     public List find(final String query) {   
  74.         return getHibernateTemplate().find(query);   
  75.     }   
  76.   
  77.     public List find(final String query, final Object parameter) {   
  78.         return getHibernateTemplate().find(query, parameter);   
  79.     }   
  80.   
  81.     public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria) {   
  82.         return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, 0);   
  83.     }   
  84.   
  85.     public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int startIndex) {   
  86.         return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, startIndex);   
  87.     }   
  88.   
  89.     public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize,   
  90.             final int startIndex) {   
  91.         return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {   
  92.             public Object doInHibernate(Session session) throws HibernateException {   
  93.                 Criteria criteria = detachedCriteria.getExecutableCriteria(session);   
  94.                 int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();   
  95.                 criteria.setProjection(null);   
  96.                 List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();   
  97.                 PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);   
  98.                 return ps;   
  99.             }   
  100.         }, true);   
  101.     }   
  102.   
  103.     public List findAllByCriteria(final DetachedCriteria detachedCriteria) {   
  104.         return (List) getHibernateTemplate().execute(new HibernateCallback() {   
  105.             public Object doInHibernate(Session session) throws HibernateException {   
  106.                 Criteria criteria = detachedCriteria.getExecutableCriteria(session);   
  107.                 return criteria.list();   
  108.             }   
  109.         }, true);   
  110.     }   
  111.   
  112.     public int getCountByCriteria(final DetachedCriteria detachedCriteria) {   
  113.         Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {   
  114.             public Object doInHibernate(Session session) throws HibernateException {   
  115.                 Criteria criteria = detachedCriteria.getExecutableCriteria(session);   
  116.                 return criteria.setProjection(Projections.rowCount()).uniqueResult();   
  117.             }   
  118.         }, true);   
  119.         return count.intValue();   
  120.     }   
  121. }   
<script type="text/javascript">render_code();</script>

 

用户在web层构造查询条件detachedCriteria,和可选的startIndex,调用业务bean的相应findByCriteria方法,返回一个PaginationSupport的实例ps。

ps.getItems()得到已分页好的结果集
ps.getIndexes()得到分页索引的数组
ps.getTotalCount()得到总结果数
ps.getStartIndex()当前分页索引
ps.getNextIndex()下一页索引
ps.getPreviousIndex()上一页索引




声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。
相关文章:    Tomcat+Mysql+UltraEdit,10分钟Hibernate初体验    Hibernate Iterator的问题
评论    共 43 条 发表评论
downpour     2005-07-16 00:04

连续看了两篇robbin有关DetachedCriteria的介绍,感觉真的不错,尤其是上面的示例代码,让我着实觉得该对我原来的分页查询做一下代码重构了。

我把原本我的做法也提供出来供大家讨论吧:

首先,为了实现分页查询,我封装了一个Page类:

代码
  1. /*Created on 2005-4-14*/  
  2. package org.flyware.util.page;   
  3.   
  4. /**  
  5.  * @author Joa  
  6.  *  
  7.  */  
  8. public class Page {   
  9.        
  10.     /** imply if the page has previous page */  
  11.     private boolean hasPrePage;   
  12.        
  13.     /** imply if the page has next page */  
  14.     private boolean hasNextPage;   
  15.            
  16.     /** the number of every page */  
  17.     private int everyPage;   
  18.        
  19.     /** the total page number */  
  20.     private int totalPage;   
  21.           
  22.     /** the number of current page */  
  23.     private int currentPage;   
  24.        
  25.     /** the begin index of the records by the current query */  
  26.     private int beginIndex;   
  27.        
  28.        
  29.     /** The default constructor */  
  30.     public Page(){   
  31.            
  32.     }   
  33.        
  34.     /** construct the page by everyPage   
  35.      * @param everyPage  
  36.      * */  
  37.     public Page(int everyPage){   
  38.         this.everyPage = everyPage;   
  39.     }   
  40.        
  41.     /** The whole constructor */  
  42.     public Page(boolean hasPrePage, boolean hasNextPage,     
  43.                  int everyPage, int totalPage,    
  44.                  int currentPage, int beginIndex) {   
  45.         this.hasPrePage = hasPrePage;   
  46.         this.hasNextPage = hasNextPage;   
  47.         this.everyPage = everyPage;   
  48.         this.totalPage = totalPage;   
  49.         this.currentPage = currentPage;   
  50.         this.beginIndex = beginIndex;   
  51.     }   
  52.   
  53.     /**  
  54.      * @return   
  55.      * Returns the beginIndex.  
  56.      */  
  57.     public int getBeginIndex() {   
  58.         return beginIndex;   
  59.     }   
  60.        
  61.     /**  
  62.      * @param beginIndex   
  63.      * The beginIndex to set.  
  64.      */  
  65.     public void setBeginIndex(int beginIndex) {   
  66.         this.beginIndex = beginIndex;   
  67.     }   
  68.        
  69.     /**  
  70.      * @return   
  71.      * Returns the currentPage.  
  72.      */  
  73.     public int getCurrentPage() {   
  74.         return currentPage;   
  75.     }   
  76.        
  77.     /**  
  78.      * @param currentPage   
  79.      * The currentPage to set.  
  80.      */  
  81.     public void setCurrentPage(int currentPage) {   
  82.         this.currentPage = currentPage;   
  83.     }   
  84.        
  85.     /**  
  86.      * @return   
  87.      * Returns the everyPage.  
  88.      */  
  89.     public int getEveryPage() {   
  90.         return everyPage;   
  91.     }   
  92.        
  93.     /**  
  94.      * @param everyPage   
  95.      * The everyPage to set.  
  96.      */  
  97.     public void setEveryPage(int everyPage) {   
  98.         this.everyPage = everyPage;   
  99.     }   
  100.        
  101.     /**  
  102.      * @return   
  103.      * Returns the hasNextPage.  
  104.      */  
  105.     public boolean getHasNextPage() {   
  106.         return hasNextPage;   
  107.     }   
  108.        
  109.     /**  
  110.      * @param hasNextPage   
  111.      * The hasNextPage to set.  
  112.      */  
  113.     public void setHasNextPage(boolean hasNextPage) {   
  114.         this.hasNextPage = hasNextPage;   
  115.     }   
  116.        
  117.     /**  
  118.      * @return   
  119.      * Returns the hasPrePage.  
  120.      */  
  121.     public boolean getHasPrePage() {   
  122.         return hasPrePage;   
  123.     }   
  124.        
  125.     /**  
  126.      * @param hasPrePage   
  127.      * The hasPrePage to set.  
  128.      */  
  129.     public void setHasPrePage(boolean hasPrePage) {   
  130.         this.hasPrePage = hasPrePage;   
  131.     }   
  132.        
  133.     /**  
  134.      * @return Returns the totalPage.  
  135.      *   
  136.      */  
  137.     public int getTotalPage() {   
  138.         return totalPage;   
  139.     }   
  140.        
  141.     /**  
  142.      * @param totalPage   
  143.      * The totalPage to set.  
  144.      */  
  145.     public void setTotalPage(int totalPage) {   
  146.         this.totalPage = totalPage;   
  147.     }   
  148.        
  149. }   
<script type="text/javascript">render_code();</script>

 

上面的这个Page类对象只是一个完整的Page描述,接下来我写了一个PageUtil,负责对Page对象进行构造:

代码
  1. /*Created on 2005-4-14*/  
  2. package org.flyware.util.page;   
  3.   
  4. import org.apache.commons.logging.Log;   
  5. import org.apache.commons.logging.LogFactory;   
  6.   
  7. /**  
  8.  * @author Joa  
  9.  *  
  10.  */  
  11. public class PageUtil {   
  12.        
  13.     private static final Log logger = LogFactory.getLog(PageUtil.class);   
  14.        
  15.     /**  
  16.      * Use the origin page to create a new page  
  17.      * @param page  
  18.      * @param totalRecords  
  19.      * @return  
  20.      */  
  21.     public static Page createPage(Page page, int totalRecords){   
  22.         return createPage(page.getEveryPage(), page.getCurrentPage(), totalRecords);   
  23.     }   
  24.        
  25.     /**    
  26.      * the basic page utils not including exception handler  
  27.      * @param everyPage  
  28.      * @param currentPage  
  29.      * @param totalRecords  
  30.      * @return page  
  31.      */  
  32.     public static Page createPage(int everyPage, int currentPage, int totalRecords){   
  33.         everyPage = getEveryPage(everyPage);   
  34.         currentPage = getCurrentPage(currentPage);   
  35.         int beginIndex = getBeginIndex(everyPage, currentPage);   
  36.         int totalPage = getTotalPage(everyPage, totalRecords);   
  37.         boolean hasNextPage = hasNextPage(currentPage, totalPage);   
  38.         boolean hasPrePage = hasPrePage(currentPage);   
  39.            
  40.         return new Page(hasPrePage, hasNextPage,     
  41.                         everyPage, totalPage,    
  42.                         currentPage, beginIndex);   
  43.     }   
  44.        
  45.     private static int getEveryPage(int everyPage){   
  46.         return everyPage == 0 ? 10 : everyPage;   
  47.     }   
  48.        
  49.     private static int getCurrentPage(int currentPage){   
  50.         return currentPage == 0 ? 1 : currentPage;   
  51.     }   
  52.        
  53.     private static int getBeginIndex(int everyPage, int currentPage){   
  54.         return (currentPage - 1) * everyPage;    
  55.     }   
  56.        
  57.     private static int getTotalPage(int everyPage, int totalRecords){   
  58.         int totalPage = 0;   
  59.            
  60.         if(totalRecords % everyPage == 0)   
  61.             totalPage = totalRecords / everyPage;    
  62.         else  
  63.             totalPage = totalRecords / everyPage + 1 ;   
  64.            
  65.         return totalPage;   
  66.     }   
  67.        
  68.     private static boolean hasPrePage(int currentPage){   
  69.         return currentPage == 1 ? false : true;    
  70.     }   
  71.        
  72.     private static boolean hasNextPage(int currentPage, int totalPage){   
  73.         return currentPage == totalPage || totalPage == 0 ? false : true;   
  74.     }   
  75.        
  76.   
  77. }   
<script type="text/javascript">render_code();</script>

 

上面的这两个对象与具体的业务逻辑无关,可以独立和抽象。

面对一个具体的业务逻辑:分页查询出User,每页10个结果。具体做法如下:
1. 编写一个通用的结果存储类Result,这个类包含一个Page对象的信息,和一个结果集List:

代码
  1. /*Created on 2005-6-13*/  
  2. package com.adt.bo;   
  3.   
  4. import java.util.List;   
  5.   
  6. import org.flyware.util.page.Page;   
  7.   
  8. /**  
  9.  * @author Joa  
  10.  */  
  11. public class Result {   
  12.   
  13.     private Page page;   
  14.   
  15.     private List content;   
  16.   
  17.     /**  
  18.      * The default constructor  
  19.      */  
  20.     public Result() {   
  21.         super();   
  22.     }   
  23.   
  24.     /**  
  25.      * The constructor using fields  
  26.      *   
  27.      * @param page  
  28.      * @param content  
  29.      */  
  30.     public Result(Page page, List content) {   
  31.         this.page = page;   
  32.         this.content = content;   
  33.     }   
  34.   
  35.     /**  
  36.      * @return Returns the content.  
  37.      */  
  38.     public List getContent() {   
  39.         return content;   
  40.     }   
  41.   
  42.     /**  
  43.      * @return Returns the page.  
  44.      */  
  45.     public Page getPage() {   
  46.         return page;   
  47.     }   
  48.   
  49.     /**  
  50.      * @param content  
  51.      *            The content to set.  
  52.      */  
  53.     public void setContent(List content) {   
  54.         this.content = content;   
  55.     }   
  56.   
  57.     /**  
  58.      * @param page  
  59.      *            The page to set.  
  60.      */  
  61.     public void setPage(Page page) {   
  62.         this.page = page;   
  63.     }   
  64. }   
<script type="text/javascript">render_code();</script>

 

2. 编写业务逻辑接口,并实现它(UserManager, UserManagerImpl)

代码
  1. /*Created on 2005-7-15*/  
  2. package com.adt.service;   
  3.   
  4. import net.sf.hibernate.HibernateException;   
  5.   
  6. import org.flyware.util.page.Page;   
  7.   
  8. import com.adt.bo.Result;   
  9.   
  10. /**  
  11.  * @author Joa  
  12.  */  
  13. public interface UserManager {   
  14.        
  15.     public Result listUser(Page page) throws HibernateException;   
  16.   
  17. }   
<script type="text/javascript">render_code();</script>

 

 

代码
  1. /*Created on 2005-7-15*/  
  2. package com.adt.service.impl;   
  3.   
  4. import java.util.List;   
  5.   
  6. import net.sf.hibernate.HibernateException;   
  7.   
  8. import org.flyware.util.page.Page;   
  9. import org.flyware.util.page.PageUtil;   
  10.   
  11. import com.adt.bo.Result;   
  12. import com.adt.dao.UserDAO;   
  13. import com.adt.exception.ObjectNotFoundException;   
  14. import com.adt.service.UserManager;   
  15.   
  16. /**  
  17.  * @author Joa  
  18.  */  
  19. public class UserManagerImpl implements UserManager {   
  20.        
  21.     private UserDAO userDAO;   
  22.   
  23.     /**  
  24.      * @param userDAO The userDAO to set.  
  25.      */  
  26.     public void setUserDAO(UserDAO userDAO) {   
  27.         this.userDAO = userDAO;   
  28.     }   
  29.        
  30.     /* (non-Javadoc)  
  31.      * @see com.adt.service.UserManager#listUser(org.flyware.util.page.Page)  
  32.      */  
  33.     public Result listUser(Page page) throws HibernateException, ObjectNotFoundException {   
  34.         int totalRecords = userDAO.getUserCount();   
  35.         if(totalRecords == 0)   
  36.             throw new ObjectNotFoundException("userNotExist");   
  37.         page = PageUtil.createPage(page, totalRecords);   
  38.         List users = userDAO.getUserByPage(page);   
  39.         return new Result(page, users);   
  40.     }   
  41.   
  42. }   
<script type="text/javascript">render_code();</script>

 

其中,UserManagerImpl中调用userDAO的方法实现对User的分页查询,接下来编写UserDAO的代码:
3. UserDAO 和 UserDAOImpl:

代码
  1. /*Created on 2005-7-15*/  
  2. package com.adt.dao;   
  3.   
  4. import java.util.List;   
  5.   
  6. import org.flyware.util.page.Page;   
  7.   
  8. import net.sf.hibernate.HibernateException;   
  9.   
  10. /**  
  11.  * @author Joa  
  12.  */  
  13. public interface UserDAO extends BaseDAO {   
  14.        
  15.     public List getUserByName(String name) throws HibernateException;   
  16.        
  17.     public int getUserCount() throws HibernateException;   
  18.        
  19.     public List getUserByPage(Page page) throws HibernateException;   
  20.   
  21. }   
<script type="text/javascript">render_code();</script>

 

 

代码
  1. /*Created on 2005-7-15*/  
  2. package com.adt.dao.impl;   
  3.   
  4. import java.util.List;   
  5.   
  6. import org.flyware.util.page.Page;   
  7.   
  8. import net.sf.hibernate.HibernateException;   
  9. import net.sf.hibernate.Query;   
  10.   
  11. import com.adt.dao.UserDAO;   
  12.   
  13. /**  
  14.  * @author Joa  
  15.  */  
  16. public class UserDAOImpl extends BaseDAOHibernateImpl implements UserDAO {   
  17.   
  18.     /* (non-Javadoc)  
  19.      * @see com.adt.dao.UserDAO#getUserByName(java.lang.String)  
  20.      */  
  21.     public List getUserByName(String name) throws HibernateException {   
  22.         String querySentence = "FROM user in class com.adt.po.User WHERE user.name=:name";   
  23.         Query query = getSession().createQuery(querySentence);   
  24.         query.setParameter("name", name);   
  25.         return query.list();    
  26.     }   
  27.   
  28.     /* (non-Javadoc)  
  29.      * @see com.adt.dao.UserDAO#getUserCount()  
  30.      */  
  31.     public int getUserCount() throws HibernateException {   
  32.         int count = 0;   
  33.         String querySentence = "SELECT count(*) FROM user in class com.adt.po.User";   
  34.         Query query = getSession().createQuery(querySentence);   
  35.         count = ((Integer)query.iterate().next()).intValue();   
  36.         return count;   
  37.     }   
  38.   
  39.     /* (non-Javadoc)  
  40.      * @see com.adt.dao.UserDAO#getUserByPage(org.flyware.util.page.Page)  
  41.      */  
  42.     public List getUserByPage(Page page) throws HibernateException {   
  43.         String querySentence = "FROM user in class com.adt.po.User";   
  44.         Query query = getSession().createQuery(querySentence);   
  45.         query.setFirstResult(page.getBeginIndex())   
  46.              .setMaxResults(page.getEveryPage());   
  47.         return query.list();   
  48.     }   
  49.   
  50. }   
<script type="text/javascript">render_code();</script>

 

至此,一个完整的分页程序完成。前台的只需要调用userManager.listUser(page)即可得到一个Page对象和结果集对象的综合体,而传入的参数page对象则可以由前台传入,如果用webwork,甚至可以直接在配置文件中指定。

下面给出一个webwork调用示例:

代码
  1. /*Created on 2005-6-17*/  
  2. package com.adt.action.user;   
  3.   
  4. import java.util.List;   
  5.   
  6. import org.apache.commons.logging.Log;   
  7. import org.apache.commons.logging.LogFactory;   
  8. import org.flyware.util.page.Page;   
  9.   
  10. import com.adt.bo.Result;   
  11. import com.adt.service.UserService;   
  12. import com.opensymphony.xwork.Action;   
  13.   
  14. /**  
  15.  * @author Joa  
  16.  */  
  17. public class ListUser implements Action {   
  18.   
  19.     private static final Log logger = LogFactory.getLog(ListUser.class);   
  20.   
  21.     private UserService userService;   
  22.   
  23.     private Page page;   
  24.   
  25.     private List users;   
  26.   
  27.     /*  
  28.      * (non-Javadoc)  
  29.      *   
  30.      * @see com.opensymphony.xwork.Action#execute()  
  31.      */  
  32.     public String execute() throws Exception {   
  33.         Result result = userService.listUser(page);   
  34.         page = result.getPage();   
  35.         users = result.getContent();   
  36.         return SUCCESS;   
  37.     }   
  38.   
  39.     /**  
  40.      * @return Returns the page.  
  41.      */  
  42.     public Page getPage() {   
  43.         return page;   
  44.     }   
  45.   
  46.     /**  
  47.      * @return Returns the users.  
  48.      */  
  49.     public List getUsers() {   
  50.         return users;   
  51.     }   
  52.   
  53.     /**  
  54.      * @param page  
  55.      *            The page to set.  
  56.      */  
  57.     public void setPage(Page page) {   
  58.         this.page = page;   
  59.     }   
  60.   
  61.     /**  
  62.      * @param users  
  63.      *            The users to set.  
  64.      */  
  65.     public void setUsers(List users) {   
  66.         this.users = users;   
  67.     }   
  68.   
  69.     /**  
  70.      * @param userService  
  71.      *            The userService to set.  
  72.      */  
  73.     public void setUserService(UserService userService) {   
  74.         this.userService = userService;   
  75.     }   
  76. }   
<script type="text/javascript">render_code();</script>

 

上面的代码似乎看不出什么地方设置了page的相关初值,事实上,可以通过配置文件来进行配置,例如,我想每页显示10条记录,那么只需要:

代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">  
  3.   
  4. <xwork>  
  5.        
  6.     <package name="user" extends="webwork-interceptors">  
  7.            
  8.         <!-- The default interceptor stack name -->  
  9.         <default-interceptor-ref name="myDefaultWebStack"/>  
  10.            
  11.         <action name="listUser" class="com.adt.action.user.ListUser">  
  12.             <param name="page.everyPage">10</param>  
  13.             <result name="success">/user/user_list.jsp</result>  
  14.         </action>  
  15.            
  16.     </package>  
  17.   
  18. </xwork>  
  19.   
<script type="text/javascript">render_code();</script>

 

这样就可以通过配置文件和OGNL的共同作用来对page对象设置初值了。并可以通过随意修改配置文件来修改每页需要显示的记录数。

注:上面的<param>的配置,还需要webwork和Spring整合的配合。

coolnight     2005-07-17 19:40

我写的一个用于分页的类,用了泛型了,hoho

 

代码
  1. package com.intokr.util;   
  2.   
  3. import java.util.List;   
  4.   
  5. /**  
  6.  * 用于分页的类<br>  
  7.  * 可以用于传递查询的结果也可以用于传送查询的参数<br>  
  8.  *   
  9.  * @version 0.01  
  10.  * @author cheng  
  11.  */  
  12. public class Paginator<E> {   
  13.     private int count = 0// 总记录数   
  14.     private int p = 1// 页编号   
  15.     private int num = 20// 每页的记录数   
  16.     private List<E> results = null// 结果   
  17.   
  18.     /**  
  19.      * 结果总数  
  20.      */  
  21.     public int getCount() {   
  22.         return count;   
  23.     }   
  24.   
  25.     public void setCount(int count) {   
  26.         this.count = count;   
  27.     }   
  28.   
  29.     /**  
  30.      * 本结果所在的页码,从1开始  
  31.      *   
  32.      * @return Returns the pageNo.  
  33.      */  
  34.     public int getP() {   
  35.         return p;   
  36.     }   
  37.   
  38.     /**  
  39.      * if(p<=0) p=1  
  40.      *   
  41.      * @param p  
  42.      */  
  43.     public void setP(int p) {   
  44.         if (p <= 0)   
  45.             p = 1;   
  46.         this.p = p;   
  47.     }   
  48.   
  49.     /**  
  50.      * 每页记录数量  
  51.      */  
  52.     public int getNum() {   
  53.         return num;   
  54.     }   
  55.   
  56.     /**  
  57.      * if(num<1) num=1  
  58.      */  
  59.     public void setNum(int num) {   
  60.         if (num < 1)   
  61.             num = 1;   
  62.         this.num = num;   
  63.     }   
  64.   
  65.     /**  
  66.      * 获得总页数  
  67.      */  
  68.     public int getPageNum() {   
  69.         return (count - 1) / num + 1;   
  70.     }   
  71.   
  72.     /**  
  73.      * 获得本页的开始编号,为 (p-1)*num+1  
  74.      */  
  75.     public int getStart() {   
  76.         return (p - 1) * num + 1;   
  77.     }   
  78.   
  79.     /**  
  80.      * @return Returns the results.  
  81.      */  
  82.     public List<E> getResults() {   
  83.         return results;   
  84.     }   
  85.   
  86.     public void setResults(List<E> results) {   
  87.         this.results = results;   
  88.     }   
  89.   
  90.     public String toString() {   
  91.         StringBuilder buff = new StringBuilder();   
  92.         buff.append("{");   
  93.         buff.append("count:").append(count);   
  94.         buff.append(",p:").append(p);   
  95.         buff.append(",nump:").append(num);   
  96.         buff.append(",results:").append(results);   
  97.         buff.append("}");   
  98.         return buff.toString();   
  99.     }   
  100.   
  101. }   
  102.   
<script type="text/javascript">render_code();</script>

 

windyboy     2005-07-19 15:43

感谢大家的分享
尤其是看到了 Projections 的咚咚
以前用Criteria的时候就是没法做count才改用HQL,现在能够这样做的话,还是相当理想的。
我看简单应用的后台分页部分这样基本上也算是圆满了,如果用tapestry,再构造一个支持后台数据库分页,排序的东西,将会带来极大的方便,嘿嘿

sailorhero     2005-08-09 22:36

今天看Robin的代码,测试了一下,发现一个问题。
public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize,
final int startIndex)
这里如果detachedCriteria中,加入了Order对象,在函数中,计算
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
criteria.setProjection(null);
会报告异常,指示Order对象有问题。
假设查询语句为:
from Person where type = 2 order by logTime

在计算总个数时,Hibernate输出的SQL语句是
select count(*) from Person where type = 2 order by logTime
语法出错。

是否在函数中,将Order对象单独处理,作为参数传入。
public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, Order order,final int pageSize,
final int startIndex){
return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
criteria.setProjection(null);
criteria.addOrder(order);
List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
return ps;
}
}, true);
}

 

robbin 写道
Hibernate3提供了DetachedCriteria,使得我们可以在Web层构造detachedCriteria,然后调用业务层Bean,进行动态条件查询,根据这一功能,我设计了通用的抽象Bean基类和分页类支持,代码来自于Quake Wang的javaeye-core包的相应类,然后又做了很多修改。

 

分页支持类:

 

java 代码
  1. package com.javaeye.common.util;   
  2.   
  3. import java.util.List;   
  4.   
  5. public class PaginationSupport {   
  6.   
  7.     public final static int PAGESIZE = 30;   
  8.   
  9.     private int pageSize = PAGESIZE;   
  10.   
  11.     private List items;   
  12.   
  13.     private int totalCount;   
  14.   
  15.     private int[] indexes = new int[0];   
  16.   
  17.     private int startIndex = 0;   
  18.   
  19.     public PaginationSupport(List items, int totalCount) {   
  20.         setPageSize(PAGESIZE);   
  21.                 setTotalCount(totalCount);   
  22.         setItems(items);           
  23.         setStartIndex(0);   
  24.     }   
  25.   
  26.     public PaginationSupport(List items, int totalCount, int startIndex) {   
  27.                 setPageSize(PAGESIZE);   
  28.         setTotalCount(totalCount);   
  29.         setItems(items);           
  30.         setStartIndex(startIndex);   
  31.     }   
  32.   
  33.     public PaginationSupport(List items, int totalCount, int pageSize, int startIndex) {   
  34.                 setPageSize(pageSize);   
  35.         setTotalCount(totalCount);   
  36.         setItems(items);   
  37.         setStartIndex(startIndex);   
  38.     }   
  39.   
  40.     public List getItems() {   
  41.         return items;   
  42.     }   
  43.   
  44.     public void setItems(List items) {   
  45.         this.items = items;   
  46.     }   
  47.   
  48.     public int getPageSize() {   
  49.         return pageSize;   
  50.     }   
  51.   
  52.     public void setPageSize(int pageSize) {   
  53.         this.pageSize = pageSize;   
  54.     }   
  55.   
  56.     public int getTotalCount() {   
  57.         return totalCount;   
  58.     }   
  59.   
  60.     public void setTotalCount(int totalCount) {   
  61.         if (totalCount > 0) {   
  62.             this.totalCount = totalCount;   
  63.             int count = totalCount / pageSize;   
  64.             if (totalCount % pageSize > 0)   
  65.                 count++;   
  66.             indexes = new int[count];   
  67.             for (int i = 0; i < count; i++) {   
  68.                 indexes[i] = pageSize * i;   
  69.             }   
  70.         } else {   
  71.             this.totalCount = 0;   
  72.         }   
  73.     }   
  74.   
  75.     public int[] getIndexes() {   
  76.         return indexes;   
  77.     }   
  78.   
  79.     public void setIndexes(int[] indexes) {   
  80.         this.indexes = indexes;   
  81.     }   
  82.   
  83.     public int getStartIndex() {   
  84.         return startIndex;   
  85.     }   
  86.   
  87.     public void setStartIndex(int startIndex) {   
  88.         if (totalCount <= 0)   
  89.             this.startIndex = 0;   
  90.         else if (startIndex >= totalCount)   
  91.             this.startIndex = indexes[indexes.length - 1];   
  92.         else if (startIndex < 0)   
  93.             this.startIndex = 0;   
  94.         else {   
  95.             this.startIndex = indexes[startIndex / pageSize];   
  96.         }   
  97.     }   
  98.   
  99.     public int getNextIndex() {   
  100.         int nextIndex = getStartIndex() + pageSize;   
  101.         if (nextIndex >= totalCount)   
  102.             return getStartIndex();   
  103.         else  
  104.             return nextIndex;   
  105.     }   
  106.   
  107.     public int getPreviousIndex() {   
  108.         int previousIndex = getStartIndex() - pageSize;   
  109.         if (previousIndex < 0)   
  110.             return 0;   
  111.         else  
  112.             return previousIndex;   
  113.     }   
  114.   
  115. }  
<script type="text/javascript">render_code();</script>

 

抽象业务类

java 代码
  1. /**  
  2.  * Created on 2005-7-12  
  3.  */  
  4. package com.javaeye.common.business;   
  5.   
  6. import java.io.Serializable;   
  7. import java.util.List;   
  8.   
  9. import org.hibernate.Criteria;   
  10. import org.hibernate.HibernateException;   
  11. import org.hibernate.Session;   
  12. import org.hibernate.criterion.DetachedCriteria;   
  13. import org.hibernate.criterion.Projections;   
  14. import org.springframework.orm.hibernate3.HibernateCallback;   
  15. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;   
  16.   
  17. import com.javaeye.common.util.PaginationSupport;   
  18.   
  19. public abstract class AbstractManager extends HibernateDaoSupport {   
  20.   
  21.     private boolean cacheQueries = false;   
  22.   
  23.     private String queryCacheRegion;   
  24.   
  25.     public void setCacheQueries(boolean cacheQueries) {   
  26.         this.cacheQueries = cacheQueries;   
  27.     }   
  28.   
  29.     public void setQueryCacheRegion(String queryCacheRegion) {   
  30.         this.queryCacheRegion = queryCacheRegion;   
  31.     }   
  32.   
  33.     public void save(final Object entity) {   
  34.         getHibernateTemplate().save(entity);   
  35.     }   
  36.   
  37.     public void persist(final Object entity) {   
  38.         getHibernateTemplate().save(entity);   
  39.     }   
  40.   
  41.     public void update(final Object entity) {   
  42.         getHibernateTemplate().update(entity);   
  43.     }   
  44.   
  45.     public void delete(final Object entity) {   
  46.         getHibernateTemplate().delete(entity);   
  47.     }   
  48.   
  49.     public Object load(final Class entity, final Serializable id) {   
  50.         return getHibernateTemplate().load(entity, id);   
  51.     }   
  52.   
  53.     public Object get(final Class entity, final Serializable id) {   
  54.         return getHibernateTemplate().get(entity, id);   
  55.     }   
  56.   
  57.     public List findAll(final Class entity) {   
  58.         return getHibernateTemplate().find("from " + entity.getName());   
  59.     }   
  60.   
  61.     public List findByNamedQuery(final String namedQuery) {   
  62.         return getHibernateTemplate().findByNamedQuery(namedQuery);   
  63.     }   
  64.   
  65.     public List findByNamedQuery(final String query, final Object parameter) {   
  66.         return getHibernateTemplate().findByNamedQuery(query, parameter);   
  67.     }   
  68.   
  69.     public List findByNamedQuery(final String query, final Object[] parameters) {   
  70.         return getHibernateTemplate().findByNamedQuery(query, parameters);   
  71.     }   
  72.   
  73.     public List find(final String query) {   
  74.         return getHibernateTemplate().find(query);   
  75.     }   
  76.   
  77.     public List find(final String query, final Object parameter) {   
  78.         return getHibernateTemplate().find(query, parameter);   
  79.     }   
  80.   
  81.     public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria) {   
  82.         return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, 0);   
  83.     }   
  84.   
  85.     public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int startIndex) {   
  86.         return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, startIndex);   
  87.     }   
  88.   
  89.     public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize,   
  90.             final int startIndex) {   
  91.         return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {   
  92.             public Object doInHibernate(Session session) throws HibernateException {   
  93.                 Criteria criteria = detachedCriteria.getExecutableCriteria(session);   
  94.                 int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();   
  95.                 criteria.setProjection(null);   
  96.                 List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();   
  97.                 PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);   
  98.                 return ps;   
  99.             }   
  100.         }, true);   
  101.     }   
  102.   
  103.     public List findAllByCriteria(final DetachedCriteria detachedCriteria) {   
  104.         return (List) getHibernateTemplate().execute(new HibernateCallback() {   
  105.             public Object doInHibernate(Session session) throws HibernateException {   
  106.                 Criteria criteria = detachedCriteria.getExecutableCriteria(session);   
  107.                 return criteria.list();   
  108.             }   
  109.         }, true);   
  110.     }   
  111.   
  112.     public int getCountByCriteria(final DetachedCriteria detachedCriteria) {   
  113.         Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {   
  114.             public Object doInHibernate(Session session) throws HibernateException {   
  115.                 Criteria criteria = detachedCriteria.getExecutableCriteria(session);   
  116.                 return criteria.setProjection(Projections.rowCount()).uniqueResult();   
  117.             }   
  118.         }, true);   
  119.         return count.intValue();   
  120.     }   
  121. }   
<script type="text/javascript">render_code();</script>

 

用户在web层构造查询条件detachedCriteria,和可选的startIndex,调用业务bean的相应findByCriteria方法,返回一个PaginationSupport的实例ps。

ps.getItems()得到已分页好的结果集
ps.getIndexes()得到分页索引的数组
ps.getTotalCount()得到总结果数
ps.getStartIndex()当前分页索引
ps.getNextIndex()下一页索引
ps.getPreviousIndex()上一页索引

 

hzlinux     2005-08-15 21:56

重要的 page的算法
http://pear.php.net/package/Pager

而不是 如何从数据库中 获取分页的数据

最好同时提供测试代码

kerberos     2005-08-25 08:56

我个人认为,如果在Web层或业务层构造detachedCriteria,会造成整个应用对hibernate的依赖,限定了data access一定要由hibernate实现,如果想要替换成其他实现就会牵涉到多个层的改动。
问题:
有没有其他的解决方案呢?

samuel_bai     2005-08-25 17:57

 

引用
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
criteria.setProjection(null);
List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
这段代码有如下几个问题:
1。如果cirteria设置了projection,这里将其改变,那么查出的items则是不正确的。因此只要将tocalcount和items的位置换一下即可了
2。如果criteria设置了order的话,那么criteria生成的sql将会有语法错误,比如order by中的某某字段不在聚合函数中,如果能将criteria的order去掉就好了,可是criteria没有这个api......

 

sakis     2005-08-26 10:09

 

samuel_bai 写道
引用
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
criteria.setProjection(null);
List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
这段代码有如下几个问题:
1。如果cirteria设置了projection,这里将其改变,那么查出的items则是不正确的。因此只要将tocalcount和items的位置换一下即可了
2。如果criteria设置了order的话,那么criteria生成的sql将会有语法错误,比如order by中的某某字段不在聚合函数中,如果能将criteria的order去掉就好了,可是criteria没有这个api......

 

- 1.cirteria设置了projection统计完rowCount后又setProjection(null),所以“基本”上应该是可行的。
- 2.这个order问题的确很伤心,我的做法是将Order[]作为一个参数传入,在rowCount统计完成后,再在criteria中加入。

这种分页做法很优美,完全把分页程序与具体表分离了,复用性很高。遗憾的是DetachedCriteria/Criteria现在实现的还不是十分完善,比如:
我用的hibernate是3.0.5,发现多次使用同一个DetachedCriteria对象后,在作rowCount projection时会出错,返回null(可前几次都返回了正确的结果)。

该方法对于单表查询应该还是没多大问题的,对于某些复杂的查询条件需要做更多的测试。

AreYouOK?     2005-08-26 12:52

 

sakis 写道
samuel_bai 写道
引用
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
criteria.setProjection(null);
List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
这段代码有如下几个问题:
1。如果cirteria设置了projection,这里将其改变,那么查出的items则是不正确的。因此只要将tocalcount和items的位置换一下即可了
2。如果criteria设置了order的话,那么criteria生成的sql将会有语法错误,比如order by中的某某字段不在聚合函数中,如果能将criteria的order去掉就好了,可是criteria没有这个api......

 

- 1.cirteria设置了projection统计完rowCount后又setProjection(null),所以“基本”上应该是可行的。
- 2.这个order问题的确很伤心,我的做法是将Order[]作为一个参数传入,在rowCount统计完成后,再在criteria中加入。

这种分页做法很优美,完全把分页程序与具体表分离了,复用性很高。遗憾的是DetachedCriteria/Criteria现在实现的还不是十分完善,比如:
我用的hibernate是3.0.5,发现多次使用同一个DetachedCriteria对象后,在作rowCount projection时会出错,返回null(可前几次都返回了正确的结果)。

该方法对于单表查询应该还是没多大问题的,对于某些复杂的查询条件需要做更多的测试。

 

1:具体的说是单表查询可以,但是如果关联其它表,或者createAlias,返回的items就会有问题,掉换顺序也不行,items里面的每个元素都是一个数组。我的解决办法是再加一个ResultTransformer参数,在setProjection(null)后再setResultTransformer

DetachedCriteria确实实现的不是很完善,我们希望它是一个无状态的,仅保存查询条件的值对象,但实际上它做不到。一个DetachedCriteria对象反复做分页查询,第一次查询时调用的setMaxResults方法和setFirstResult方法后,这个状态保存在DetachedCriteria上了,会影响下一次count操作,因此每次查询必需new一个DetachedCriteria。同样的原因导致第一个问题交换操作顺序也不行。

zhangzhiya     2005-08-29 18:14

经典啊!!感谢大家分享这么多!
只不过有些地方看得不是太懂!
需要自己复制下来测一下。。
如果能把测试类能写出来就更好了~~再次谢谢大家。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值