大话分页(一)

分页是一项人性化的功能,也是查看大量显示数据的一种解决方案。然而就分页功能的实现来说,分页是多种多样的。那我们在项目中用到的时候,我该使用哪种方式进行分页呢?下面我将汇总一下分页查询的各种实现,并加以比对,当你使用时,做出较好的选择(本文讨论范畴只在真分页,下面谈到的分页也特指真分页)。

分页共性

凡是分页,无论使用什么方式实现,它都是以从第几条数据到第几条数据这样的思路实现的,都需要提供两个参数:

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?

  1. public class AbstractPageManager extends HibernateDaoSupport {
  2. /**
  3. * 根据HQL语句,获得查找总记录数的HQL语句 如:
  4. * select ... from Organization o where o.parent is null
  5. * 经过转换,可以得到:
  6. * select count(*) from Organization o where o.parent is null
  7. *
  8. * @param hql
  9. * @return
  10. */
  11. private String getCountQuery(String hql) {
  12. // 取得from的位置
  13. int index = hql.indexOf("from");
  14. // 返回:查询记录条数 的SQL语句
  15. if (index != -1) {
  16. return "select count(*) " + hql.substring(index);
  17. }
  18. throw new SystemException("无效的HQL查询语句");
  19. }
  20. /**
  21. * 根据HQL语句进行分页查询
  22. *
  23. * @param hql HQL语句
  24. * @param params HQL语句带的多个参数
  25. * @param offSet 从第几个记录开始查询
  26. * @param pageSize 每页显示多少行
  27. * @return
  28. */
  29. public PageModel searchPaginate(String hql, Object[] params, int offSet,
  30. int pageSize) {
  31. // 记录条数
  32. String strCount = getCountQuery(hql);
  33. // 查询条数
  34. Query query = getSession().createQuery(strCount);
  35. // 将HQL语句带的多个参数 赋值给Query
  36. if (params != null && params.length > 0) {
  37. for (int i = 0; i < params.length; i++) {
  38. query.setParameter(i, params[i]);
  39. }
  40. }
  41. // 获取查询条数
  42. int intCount = ((Long) query.uniqueResult()).intValue();
  43. // 查询Organization记录
  44. query = getSession().createQuery(hql);
  45. // 将HQL语句带的多个参数 赋值给Query
  46. if (params != null && params.length > 0) {
  47. for (int i = 0; i < params.length; i++) {
  48. query.setParameter(i, params[i]);
  49. }
  50. }
  51. /*
  52. * offSet 设置从第几个记录开始查询
  53. * pageSize 设置每页显示多少行
  54. */
  55. query.setFirstResult(offSet);
  56. query.setMaxResults(pageSize);
  57. //组装PageModel
  58. PageModel pageModel = new PageModel();
  59. pageModel.setDatas(query.list());
  60. pageModel.setTotal(intCount);
  61. return pageModel;
  62. }
  63. }
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源码,我这里就不往上贴了。

未完待续。。

时间: 2024-08-02 06:49:55

大话分页(一)的相关文章

大话 程序猿 眼里的 接口

开场 魂淡别碰的孩子(接口), 作为后端程序猿自己写的接口就像自己的孩子一样,尽然制造出来了,那就要对他以后的人生负责到底:随着业务的壮大,需要支撑业务接口也越来越多,使用的用户量变大,虎视眈眈的黑客们视机而动,总是在业务中寻找着可以窃取他人利益的入口,所以我们应该多考虑安全性问题,防范于未然. 场景 服务端程序猿根据需求开发出业务相关的接口,用来满足需求中用户和服务器交互的功能,提供给前端或者客户端(PC端软件,APP端应用)使用, 大部分程序猿在开发接口的时候就仅仅去考虑如何实现业务上的逻辑

python__Django 分页

自定义分页的类: #!/usr/bin/env python # -*- coding: utf-8 -*- # Created by Mona on 2017/9/20 from django.utils.safestring import mark_safe class Paginator: ''' 页码的格式依赖于bootstrap: 使用案例: from django.shortcuts import render,redirect,HttpResponse from app01.mod

ajax+分页

<!DOCTYPE html><html><head lang="zh-cn"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><meta http-equiv="X-UA-Compat

使用插件bootstrap-table实现表格记录的查询、分页、排序等处理

在业务系统开发中,对表格记录的查询.分页.排序等处理是非常常见的,在Web开发中,可以采用很多功能强大的插件来满足要求,且能极大的提高开发效率,本随笔介绍这个bootstrap-table是一款非常有名的开源表格插件,在很多项目中广泛的应用.Bootstrap-table插件提供了非常丰富的属性设置,可以实现查询.分页.排序.复选框.设置显示列.Card view视图.主从表显示.合并列.国际化处理等处理功能,而且该插件同时也提供了一些不错的扩展功能,如移动行.移动列位置等一些特殊的功能,插件可

优化LIMIT分页

在系统中需要分页的操作通常会使用limit加上偏移量的方法实现,同时加上合适的order by 子句.如果有对应的索引,通常效率会不错,否则MySQL需要做大量的文件排序操作. 一个非常令人头疼问题就是当偏移量非常大的时候,例如可能是limit 10000,20这样的查询,这是mysql需要查询10020条然后只返回最后20条,前面的10000条记录都将被舍弃,这样的代价很高.如果所有的页面被访问的频率相同,那么这样的查询平均需要访问半个表的数据.要优化这样的查询,要么实在页面中限制分页的数量,

SQL SERVER大话存储结构(5)

阅读目录(Content) 1 基本介绍 2 对数据库启动的影响 3 日志文件添加方式 4 物理结构 5 延迟日志截断原因 6 管理事务日志 本系列上一篇博文链接:SQL SERVER大话存储结构(4)_复合索引与包含索引 回到顶部(go to top) 1 基本介绍 每个数据库都具有事务日志,用于记录所有事物以及每个事物对数据库所作的操作. 日志的记录形式需要根据数据库的恢复模式来确定,数据库恢复模式有三种: 完整模式,完全记录事物日志,需要定期进行日志备份. 大容量日志模式,适用于批量操作的

Ajax实现无刷新分页

注:本文中使用到的一些类库在前面文章都能找到源代码,我会在文中指明链接所在,为了缩短文章篇幅,由此带来的阅读不便,敬请谅解. 本文讲解 Ajax 实现无刷新分页.实现原理.代码展示.代码下载. 这里需要说明一些知识: 1.Ajax 无刷新页面的好处:提供良好的客户体验,通过 Ajax 在后台从数据库中取得数据并展示,取缔了等待加载页面而出现的空白状态: 2.那么,Ajax 无刷新页面是运行在动态页面(.PHP)?还是静态页面(.html/.htm/.shtml)?答案是:静态页面: 3.实现原理

关于分页SQL的小总结

findPage 和findPageTotal条件分页中的条件 较为复杂点的关联查询 有取别名的 <select id="findPage" resultMap="MinOrderInfo" parameterType="map"> SELECT o.*,w.name buyName,w.MOBILE buyMobile,aa.name sellName,aa.MOBILE sellMobile,rs.CAR_BRAND_NAME c

webform:分页组合查询

一个简单的分页组合查询页面 /// <summary> /// 查询方法 /// </summary> /// <param name="tsql">SQL语句</param> /// <param name="hh">哈希表</param> /// <returns></returns> public List<Goods> Select(string un