Hibernate分页查询

来源:互联网 发布:数据库工程师待遇知乎 编辑:程序博客网 时间:2024/05/17 01:48


通常使用的Hibernate通常是三种:hql查询,QBC查询和QBE查询:
1、QBE(Qurey By Example)检索方式
QBE是最简单的,但是功能也是最弱的,QBE的功能不是特别强大,仅在某些场合下有用。一个典型的使用场合就是在查询窗口中让用户输入一系列的查询条件,然后返回匹配的对象。QBE只支持=和like比较运算符,无法不大区间值,及其或的匹配。在这种情况下,还是采用HQL检索方式或QBC检索方式。
Java代码  

public Pager findPageByExample(int pageNo, int pageSize, Object object)   {       Pager pager = null;       try      {           Criteria criteria = this.getSession().createCriteria(                   Class.forName(this.getEntity()));             if (object != null)           {               criteria.add(Example.create(object).enableLike());           }             // 获取根据条件分页查询的总行数           int rowCount = (Integer) criteria.setProjection(                   Projections.rowCount()).uniqueResult();           criteria.setProjection(null);             criteria.setFirstResult((pageNo - 1) * pageSize);           criteria.setMaxResults(pageSize);             List result = criteria.list();             pager = new Pager(pageSize, pageNo, rowCount, result);         } catch (RuntimeException re)       {           throw re;       } finally      {           return pager;       }     }  



注意代码的第20行,即criteria.add(Example.create(object).enableLike());这一行,需将Example.create(object)调用.enableLike()方法,不然不能模糊查询。
在BO层将需要模糊查询的列用"%%"串起来,不然仍然和"="一样。
BO层代码:
Java代码  
public Pager getInfoByQuery(int pageNo, int pageSize, String mendName,           String specialty, String post)   {         EicMend eicMend = new EicMend();       if (mendName != null && mendName.length() > 0)       {           eicMend.setMendname("%" + mendName + "%");       }       if (specialty != null && specialty.length() > 0)       {           eicMend.setSpecialty(specialty);       }       if (post != null && post.length() > 0)       {           eicMend.setPost(post);       }         Pager pager = erpManagerDao               .findPageByExample(pageNo, pageSize, eicMend);       return pager;   }  




执行SQL语句如下:
Sql代码  
Hibernate: select count(*) as y0_ from YJZX.EIC_MEND this_ where    
(this_.MENDNAME like ? and this_.POST like ?)   
  
Hibernate: select * from ( select this_.MENDID as MENDID23_0_, ……   
this_.EXPERTREMARK as EXPERTR28_23_0_ from YJZX.EIC_MEND this_ where    
(this_.MENDNAME like ? and this_.POST like ?) ) where rownum <= ?  


所以只需将需模糊查询的列用“%%”链接即可。


2、QBC(Qurey By Criteria)检索方式
       采用HQL检索方式时,在应用程序中需要定义基于字符串形式的HQL查询语句。QBC API提供了检索对象的另一种方式,它主要由Criteria接口、Criterion接口和Restrictions接口组成,它支持在运行时动态生成查询语句。比较常见的是两种传参方式:一种是用map传参,另一种是用Criterion…不定参数传参。
Map传参方式范例如下:
DAO层:
Java代码  
public Pager findPageByCriteria(int pageNo, int pageSize, Map map)   {       Pager pager = null;       try      {           Criteria criteria = this.getSession().createCriteria(                   Class.forName(this.getEntity()));             if (map != null)           {               Set<String> keys = map.keySet();               for (String key : keys)               {                   criteria.add(Restrictions.like(key, map.get(key)));               }           }             // 获取根据条件分页查询的总行数           int rowCount = (Integer) criteria.setProjection(                   Projections.rowCount()).uniqueResult();           criteria.setProjection(null);             criteria.setFirstResult((pageNo - 1) * pageSize);           criteria.setMaxResults(pageSize);             List result = criteria.list();             pager = new Pager(pageSize, pageNo, rowCount, result);         } catch (RuntimeException re)       {           throw re;       } finally      {           return pager;       }     }  



Map传参方式对应BO层代码:
Java代码  
public Pager getInfoByQuery2(int pageNo, int pageSize, String mendName,           String specialty, String post)   {         Map map = new HashMap();         if (mendName != null && mendName.length() > 0)       {           map.put("mendname", "%" + mendName + "%");       }       if (specialty != null && specialty.length() > 0)       {           map.put("specialty", specialty);       }       if (post != null && post.length() > 0)       {           map.put("post", post);       }         Pager pager = erpManagerDao.findPageByCriteria(pageNo, pageSize, map);       return pager;   }  





第二种方式:Criterion…不定参数传参方式。其代码如下所示:
DAO层代码:
Java代码  
public Pager findPageByCriteria(int pageNo, int pageSize,           Criterion... criterions)   {       Pager pager = null;       try      {           Criteria criteria = this.getSession().createCriteria(                   Class.forName(this.getEntity()));           if (criterions != null)           {               for (Criterion criterion : criterions)               {                   if (criterion != null)                   {                       criteria.add(criterion);                   }                 }           }             // 获取根据条件分页查询的总行数           int rowCount = (Integer) criteria.setProjection(                   Projections.rowCount()).uniqueResult();           criteria.setProjection(null);             criteria.setFirstResult((pageNo - 1) * pageSize);           criteria.setMaxResults(pageSize);             List result = criteria.list();             pager = new Pager(pageSize, pageNo, rowCount, result);         } catch (RuntimeException re)       {           throw re;       } finally      {           return pager;       }     }  



Criterion…不定参数传参方式对应BO层代码:
Java代码  
public Pager getInfoByQuery3(int pageNo, int pageSize, String mendName,           String specialty, String post)   {       Criterion criterion1 = null, criterion2 = null, criterion3 = null;       if (mendName != null && mendName.length() > 0)       {           criterion1 = Restrictions.ilike("mendname", mendName,                   MatchMode.ANYWHERE);       }         if (specialty != null && specialty.length() > 0)       {           criterion2 = Restrictions.ilike("specialty", specialty,                   MatchMode.EXACT);       }         if (post != null && post.length() > 0)       {           criterion3 = Restrictions.ilike("post", post, MatchMode.EXACT);       }         Pager pager = erpManagerDao.findPageByCriteria(pageNo, pageSize,               criterion1, criterion2, criterion3);         return pager;   }  




3、HQL检索方式


HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相识。在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。
使用Query接口分页查询DAO代码:
Java代码  
public List<Object> findPageByQuery(int pageNo, int pageSize, String hql,           Map map)   {       List<Object> result = null;       try      {           Query query = this.getSession().createQuery(hql);             Iterator it = map.keySet().iterator();           while (it.hasNext())           {               Object key = it.next();               query.setParameter(key.toString(), map.get(key));           }             query.setFirstResult((pageNo - 1) * pageSize);           query.setMaxResults(pageSize);             result = query.list();         } catch (RuntimeException re)       {           throw re;       }       return result;   }  





查询所有记录数的DAO代码:
Java代码  
public int getTotalCount(String hql, Map map)   {       try      {           Query query = this.getSession().createQuery(hql);             Iterator it = map.keySet().iterator();           while (it.hasNext())           {               Object key = it.next();               query.setParameter(key.toString(), map.get(key));           }             Integer i = (Integer) query.list().get(0);           return i;       } catch (RuntimeException re)       {           throw re;       }     }  





BO层代码:
Java代码  
public Pager getInfoByQuery(int pageNo, int pageSize, String expertName,           String expertSpecialty, String post)   {       StringBuffer hql = new StringBuffer();       hql.append("select count(expertid) from EicExpert where 1=1 ");         Map map = new HashMap();         if (expertName != null && expertName.length() > 0)       {           map.put("expertname", "%" + expertName + "%");           hql.append("and expertname like :expertname ");       }       if (expertSpecialty != null && expertSpecialty.length() > 0)       {           map.put("expertspecialty", expertSpecialty);           hql.append("and expertspecialty like :expertspecialty ");       }       if (post != null && post.length() > 0)       {           map.put("post", post);           hql.append("and post like :post ");       }         String queryHql = hql.substring(22);       List result = erpManagerDao.findPageByQuery(pageNo, pageSize,               queryHql, map);       int rowCount = erpManagerDao.getTotalCount(hql.toString(), map);         Pager pager = new Pager(pageSize, pageNo, rowCount, result);       return pager;   }  






======================================================================================

======================================================================================

======================================================================================




在进行web应用开发的时候经常要进行分页处理,经常看到一些人在问分页处理的问题,现在我把自己的处理方法写在这儿,希望能对需要进行分页处理的朋友有所帮助。

一、在struts中分页有两种结构:
1. 在Action中通过DAO查询出所有的记录,然后加到session或request对象中,传到客户端,由JSP进行分页。
这种方法对于在数据量少的时候很方便,也不影响速度。
2.在Action中每次通过DAO只查询出一页的记录,再传给JSP页面。
这种结构对于数据量大的程序很好,但对于数据量小的情况,会增加对服务器的请求,加大服务器的负载。
二、Hibernate查询
由于在Hibernate中直接提供了对数据库定点定量的查询方法,所以我采用的是第2种方法。

如:
从第1万条开始取出100条记录

Query q = session.createQuery("from Cat as c");


q.setFirstResult(10000);
q.setMaxResults(100);
List l = q.list();

三、具体实现

1.Pager类

package com.jpcf.db.helper;

import java.math.*;

public class Pager {
private int totalRows; //总行数
private int pageSize = 10; //每页显示的行数
private int currentPage; //当前页号
private int totalPages; //总页数
private int startRow; //当前页在数据库中的起始行

public Pager() {
}

public Pager(int _totalRows) {
totalRows = _totalRows;
totalPages=totalRows/pageSize;
int mod=totalRows%pageSize;
if(mod>0){
totalPages++;
}
currentPage = 1;
startRow = 0;
}

public int getStartRow() {
return startRow;
}

public int getTotalPages() {
return totalPages;
}

public int getCurrentPage() {
return currentPage;
}

public int getPageSize() {
return pageSize;
}

public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}

public void setStartRow(int startRow) {
this.startRow = startRow;
}

public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}

public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}

public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}

public int getTotalRows() {
return totalRows;
}

public void first() {
currentPage = 1;
startRow = 0;
}

public void previous() {
if (currentPage == 1) {
return;
}
currentPage--;
startRow = (currentPage - 1) * pageSize;
}

public void next() {
if (currentPage < totalPages) {
currentPage++;
}
startRow = (currentPage - 1) * pageSize;
}

public void last() {
currentPage = totalPages;
startRow = (currentPage - 1) * pageSize;
}

public void refresh(int _currentPage) {
currentPage = _currentPage;
if (currentPage > totalPages) {
last();
}
}

}

Pager类用于计算首页、前一页、下一页、尾页的在数据库中的起始行,当前的页码。

2.PagerHelp类

package com.jpcf.db.helper;

import javax.servlet.http.*;

public class PagerHelper {

public static Pager getPager(HttpServletRequest httpServletRequest,
int totalRows) {

//定义pager对象,用于传到页面
Pager pager = new Pager(totalRows);

//从Request对象中获取当前页号
String currentPage = httpServletRequest.getParameter("currentPage");

//如果当前页号为空,表示为首次查询该页
//如果不为空,则刷新pager对象,输入当前页号等信息
if (currentPage != null) {
pager.refresh(Integer.parseInt(currentPage));
}

//获取当前执行的方法,首页,前一页,后一页,尾页。
String pagerMethod = httpServletRequest.getParameter("pageMethod");

if (pagerMethod != null) {
if (pagerMethod.equals("first")) {
pager.first();
} else if (pagerMethod.equals("previous")) {
pager.previous();
} else if (pagerMethod.equals("next")) {
pager.next();
} else if (pagerMethod.equals("last")) {
pager.last();
}
}
return pager;
}
}

PageHelper这个类,我不用说应该也知道用来干嘛了

3.DAO类

package com.jpcf.db.dao;

import com.jpcf.db.model.*;
import com.jpcf.db.helper.HibernateUtil;
import net.sf.hibernate.*;
import java.util.*;
import com.jpcf.db.controller.*;

public class VehiclePropertyDAO {

public Collection findWithPage(int pageSize, int startRow) throws
HibernateException {
Collection vehicleList = null;
Transaction tx = null;
try {
Session session = HibernateUtil.currentSession();
tx = session.beginTransaction();
Query q = session.createQuery("from VehicleProperty vp");
q.setFirstResult(startRow);
q.setMaxResults(pageSize);
vehicleList = q.list();
tx.commit();
} catch (HibernateException he) {
if (tx != null) {
tx.rollback();
}
throw he;
} finally {
HibernateUtil.closeSession();
}
return vehicleList;
}

public int getRows(String query) throws
HibernateException {
int totalRows = 0;
Transaction tx = null;
try {
Session session = HibernateUtil.currentSession();
tx = session.beginTransaction();
totalRows = ((Integer) session.iterate(query).next()).
intValue();
tx.commit();
} catch (HibernateException he) {
if (tx != null) {
tx.rollback();
}
throw he;
} finally {
HibernateUtil.closeSession();
}

return totalRows;
}

}
DAO类我就贴这些分页需要的代码了。
“from VehicleProperty vp”也可以用一个参数传进来,有兴趣的自己改一下吧

4.Action

下面是在Action中用到的代码:/
public ActionForward queryWithPage(ActionMapping actionMapping,
ActionForm actionForm,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletresponse) {

Collection clInfos = null;//用于输出到页面的记录集合

int totalRows;//记录总行数

VehiclePropertyDAO vehicleDAO = new VehiclePropertyDAO();

//取得当前表中的总行数
try {
totalRows = vehicleDAO.getRows("select count(*) from VehicleProperty");
} catch (Exception ex) {
servlet.log(ex.toString());
return actionMapping.findForward(Constants.FAILURE);
}

//通过PagerHelper类来获取用于输出到页面的pager对象
Pager pager=PagerHelper.getPager(httpServletRequest,totalRows);

//取出从startRow开始的pageSize行记录
try {
clInfos = vehicleDAO.findWithPage(pager.getPageSize(), pager.getStartRow());
} catch (Exception ex) {
servlet.log(ex.toString());
return actionMapping.findForward(Constants.FAILURE);
}

//把输出的记录集和pager对象保存到request对象中
httpServletRequest.setAttribute("CLINFOS", clInfos);
httpServletRequest.setAttribute("PAGER", pager);

return actionMapping.findForward(Constants.SUCCESS);
}

查询语句select count(*) from VehicleProperty 也可以换成你需要的任意的条件(select count(*) from VehicleProperty where ..)


5.JSP页面使用

下面就是在JSP中的应用了:


第页 
共页 
="/bussiness/clInfo/queryWithPage.do?method=queryWithPage&pageMethod=first
上一页
下一页
尾页
" paramName="PAGER" paramProperty="currentPage" paramId="currentPage">首页

解释一下这一行:"/bussiness/clInfo/queryWithPage.do?method=queryWithPage&pageMethod=first
method=queryWithPage 是由于我的Action继承的是DispatchAction,需要一个method参数
pageMethod=first 是用来在PageHelper类中判断执行哪个操作

四、总结

我做的这个也只是一个借鉴,还有很多没有实现的,比如还可以加一下 go 直接到第n页的功能。

其实最关键的是把当前页号和要执行的是功能(上一页,下一页)的参数从页面传进来,在Action中就可以根据这两个参数去取下一个页面上要显示的记录集了



原创粉丝点击