分页是一项人性化的功能,也是查看大量显示数据的一种解决方案。然而就分页功能的实现来说,分页是多种多样的。那我们在项目中用到的时候,我该使用哪种方式进行分页呢?下面我将汇总一下分页查询的各种实现,并加以比对,当你使用时,做出较好的选择(本文讨论范畴只在真分页,下面谈到的分页也特指真分页)。
分页共性
凡是分页,无论使用什么方式实现,它都是以从第几条数据到第几条数据这样的思路实现的,都需要提供两个参数:
PageNo:当前页号;
PaseSize:每页显示的数据。
三种数据的分页方式的比较
MySql数据库特色分页
最简单的方法就是利用mysql数据库的limit函数进行分页:
limit[offset],rows可以从Mysql数据库中第M条记录开始检索N条记录的语句为:
select * from 表名 limit M,N
从表Sys_option(主键为sys_id)中从第10条记录开始检索20条记录,语句如下:
select * from sys_option order by sys_id limit 10,20
Oracle数据库常用分页
Oracle中经常使用三层嵌套查询:
select * from (select T.*,rownum rn from (select * from table order by id) T where rownum <PageNo*PageSize) where rn >=(PageNo-1)*PageSize
PageNo为当前页数;
PageSize为每页显示数据数目。
查询的是从第(PageNo-1)*PageSize条数据到第PageNo*PageSize条数据。
例子:从t_student表中取出第20到40条数据
select * from (select A.*,rownum rn from (select * from t_student order by id) A where rownum <41) where rn >=20
问为什么Oracle要使用三层嵌套查询实现分页呢?
其实这跟Oracle数据库的特性有关,rownum的赋值默认从1开始。如果不适用嵌套查询,我们会写出下面的语句:
select rownum,id from (select * from t_student order by id) where rownum >=m and rownum < n;
当执行 rownum>m 且 m>1 时,由于rownum默认为1,这也就是一个不成立的条件,所以会查不出数据,所以采用三层嵌套语句,将rownum变成一个临时表的字段,这时候就没有oracle数据特性的限制了。
SqlServer数据常用分页
查询第一页的五条数据比较好查询,那么怎样查询第二页的数据呢(也就是第6到第10条记录)?
第二页的记录就是紧跟这第一页显示的记录之后的5条记录,也就是通过对userID字段进行降序排列时,它们是除了第一页数据之后的5条记录,也就是它们的userID不在第一页的UserID之中,在SQL语句有一个not in这个正好可以排上用场。 首先我们按照对UserID进行降序排序,查询出前面第一页使用的数据的UserID,SQL语句及执行结果如下:
select top 5 * from t_User where userID not in (select 5 userID from t_User order by userID asc) order by userID asc
userID是从1开始,所以userID在1至5的记录在第一页显示,userID为6至10的记录在第二页显示,userID为11至15的记录在第三页显示……依此类推,如果每页显示5条记录,那么第n页显示的数据记录的公式应该是:
select top 5 * from t_User where userID not in (select top(n-1)*5 userID from t_User order by userID asc) order by userID asc
Hibernate框架的分页
根据上面我们可以看出:每种数据都有自己特色的内容可以完成分页功能。Hibernate框架再此基础上进行封装,只需要Query接口中setMaxResultsset和FirstResult方法即可完成分页。采用Hibernate的好处就是:如果你使用的mysql数据库,那么Hibernate就会按照Mysql的规则生成相应的分页语句;如果使用Oracle数据库,那么它也会相应的生成对应的Oracle分页语句。也就是说,Hibernate框架实现分页,与具体数据库是无关的,有利于更换数据库。
下面看一个Hibernate实现分页的工具类的主要方法:
[java] view plaincopyprint?
- public class AbstractPageManager extends HibernateDaoSupport {
- /**
- * 根据HQL语句,获得查找总记录数的HQL语句 如:
- * select ... from Organization o where o.parent is null
- * 经过转换,可以得到:
- * select count(*) from Organization o where o.parent is null
- *
- * @param hql
- * @return
- */
- private String getCountQuery(String hql) {
- // 取得from的位置
- int index = hql.indexOf("from");
- // 返回:查询记录条数 的SQL语句
- if (index != -1) {
- return "select count(*) " + hql.substring(index);
- }
- throw new SystemException("无效的HQL查询语句");
- }
- /**
- * 根据HQL语句进行分页查询
- *
- * @param hql HQL语句
- * @param params HQL语句带的多个参数
- * @param offSet 从第几个记录开始查询
- * @param pageSize 每页显示多少行
- * @return
- */
- public PageModel searchPaginate(String hql, Object[] params, int offSet,
- int pageSize) {
- // 记录条数
- String strCount = getCountQuery(hql);
- // 查询条数
- Query query = getSession().createQuery(strCount);
- // 将HQL语句带的多个参数 赋值给Query
- if (params != null && params.length > 0) {
- for (int i = 0; i < params.length; i++) {
- query.setParameter(i, params[i]);
- }
- }
- // 获取查询条数
- int intCount = ((Long) query.uniqueResult()).intValue();
- // 查询Organization记录
- query = getSession().createQuery(hql);
- // 将HQL语句带的多个参数 赋值给Query
- if (params != null && params.length > 0) {
- for (int i = 0; i < params.length; i++) {
- query.setParameter(i, params[i]);
- }
- }
- /*
- * offSet 设置从第几个记录开始查询
- * pageSize 设置每页显示多少行
- */
- query.setFirstResult(offSet);
- query.setMaxResults(pageSize);
- //组装PageModel
- PageModel pageModel = new PageModel();
- pageModel.setDatas(query.list());
- pageModel.setTotal(intCount);
- return pageModel;
- }
- }
public class AbstractPageManager extends HibernateDaoSupport { /** * 根据HQL语句,获得查找总记录数的HQL语句 如: * select ... from Organization o where o.parent is null * 经过转换,可以得到: * select count(*) from Organization o where o.parent is null * * @param hql * @return */ private String getCountQuery(String hql) { // 取得from的位置 int index = hql.indexOf("from"); // 返回:查询记录条数 的SQL语句 if (index != -1) { return "select count(*) " + hql.substring(index); } throw new SystemException("无效的HQL查询语句"); } /** * 根据HQL语句进行分页查询 * * @param hql HQL语句 * @param params HQL语句带的多个参数 * @param offSet 从第几个记录开始查询 * @param pageSize 每页显示多少行 * @return */ public PageModel searchPaginate(String hql, Object[] params, int offSet, int pageSize) { // 记录条数 String strCount = getCountQuery(hql); // 查询条数 Query query = getSession().createQuery(strCount); // 将HQL语句带的多个参数 赋值给Query if (params != null && params.length > 0) { for (int i = 0; i < params.length; i++) { query.setParameter(i, params[i]); } } // 获取查询条数 int intCount = ((Long) query.uniqueResult()).intValue(); // 查询Organization记录 query = getSession().createQuery(hql); // 将HQL语句带的多个参数 赋值给Query if (params != null && params.length > 0) { for (int i = 0; i < params.length; i++) { query.setParameter(i, params[i]); } } /* * offSet 设置从第几个记录开始查询 * pageSize 设置每页显示多少行 */ query.setFirstResult(offSet); query.setMaxResults(pageSize); //组装PageModel PageModel pageModel = new PageModel(); pageModel.setDatas(query.list()); pageModel.setTotal(intCount); return pageModel; } }
由上可知:MySql、Oracle和SqlServer三种数据库有通性的地方,同时也有自己特色的内容。如果使用数据库特色的语句,是不利于数据库的移植的。Hibernate框架在此基础上进行封装,只需要通过setMaxResultsset()和FirstResult()方法设置offSet和pageSize,就能根据数据库生成特色语句,具体实现有兴趣的同学可以自行研究Hibernate源码,我这里就不往上贴了。
未完待续。。