赞
踩
在日常的开发中,做数据分页是很常见的需求了,面对各种各样的数据库或者是多数据源,有没有一种可以共用的实现方法呢,在明确数据量不大的情况下,逻辑分页不失为一种快速通用的方法,因为无须对sql语句进行修改,可以无视底层数据库的类型,不过这种方式的缺点也是显而易见的,一来就是效率低,二来会对应用端服务造成压力,所以一般情况下我们都会使用物理分页,把具体的实现和运算交给数据库服务。
物理分页的方式由数据库提供,效率高,但是不同的数据库对于分页的实现各有差异,所以首先要看一下不同数据库对于分页的sql实现:
在开始之前,我们首先定义几个常量,用以标记我们在具体实现中要替换的变量值:
String sqlMark = "#SQL"; 本次分页的原有sql语句,例如:select * from order_info
String startMark = "#START_COUNT"; 本次分页的开始行数
String endMark = "#END_COUNT"; 本次分页的结束行数
String orderMark = "#ORDER"; 本次分页的排序列(仅针对sqlserver)
String columnNames = "#COLUMN_NAMES"; 本次分页最后要返回的列名(按需拿部分列或全部)
MySQL
select #COLUMN_NAMES from (#SQL) A limit #START_COUNT,#END_COUNT
SQL Server
select #COLUMN_NAMES from (select *,ROW_NUMBER() OVER(order by #ORDER ) AS RowId from (#SQL) AS A ) AS B where RowId between #START_COUNT and #END_COUNT
Oracle
SELECT #COLUMN_NAMES FROM (SELECT A.*,ROWNUM RN FROM (#SQL) A WHERE ROWNUM <=#END_COUNT) WHERE RN >=#START_COUNT
SELECT #COLUMN_NAMES FROM (SELECT row_number() over (ORDER BY #ORDER) AS rn,tb.* FROM (#SQL) tb) t WHERE rn > #START_COUNT AND rn < #END_COUNT
以上就是核心内容,下面来一个具体案例,一个通用的sql查询分页方法:
- private Map<String,Object> startPage4Preview(String dbId, String sql, int pageIndex, int pageSize,Boolean noPagination) throws BusinessException, SQLException, RucException, IOException {
-
- Map<String, String> dbs = new HashMap<>();
-
- String sqlMark = "#SQL";
- String startMark = "#START_COUNT";
- String endMark = "#END_COUNT";
- String orderMark = "#ORDER";
- String columnNames = "#COLUMN_NAMES";
-
- dbs.put("oracle", "SELECT #COLUMN_NAMES FROM (SELECT A.*,ROWNUM RN FROM (#SQL) A WHERE ROWNUM <=#END_COUNT) WHERE RN >=#START_COUNT");
- dbs.put("mysql", "select #COLUMN_NAMES from (#SQL) A limit #START_COUNT,#END_COUNT");
- dbs.put("sqlserver", "select #COLUMN_NAMES from (select *,ROW_NUMBER() OVER(order by #ORDER ) AS RowId from (#SQL) AS A ) AS B where RowId between #START_COUNT and #END_COUNT");
- dbs.put("hive","SELECT #COLUMN_NAMES FROM (SELECT row_number() over (ORDER BY #ORDER) AS rn,tb.* FROM (#SQL) tb) t WHERE rn > #START_COUNT AND rn < #END_COUNT");
-
- boolean isFirstPage=false;
- boolean isLastPage=false;
- boolean haveNexPage=false;
- boolean havePerPage=false;
-
- Integer totalPage;
-
- //获取查询到的总行数
- int totalRow=getSqlCounts(dbId, sql);
-
- if (noPagination!=null&&noPagination&&totalRow>0){
- pageSize = totalRow;
- }
- int fromIndex=(pageIndex-1)*pageSize;
- int toIndex=pageIndex*pageSize;
- if(fromIndex==0) {
- isFirstPage=true;
- }else {
- havePerPage=true;
- }
- if(toIndex>=totalRow) {
- toIndex=totalRow;
- isLastPage=true;
- }else if (!isLastPage) {
- haveNexPage=true;
- }
- if(totalRow%pageSize==0) {
- totalPage=totalRow/pageSize;
- }else {
- totalPage=totalRow/pageSize+1;
- }
-
- Map<String,Object> map=new HashMap<>();
- map.put("pageIndex", pageIndex);
- map.put("totalPage", totalPage);
- map.put("totalCount", totalRow);
- map.put("pageSize", pageSize);
- map.put("firstPage", isFirstPage);
- map.put("lastPage", isLastPage);
- map.put("haveNexPage", haveNexPage);
- map.put("havePerPage", havePerPage);
-
- String dbType = getConnectionType(dbId);
- String newSQL = dbs.get(dbType).replace(sqlMark, sql);
- if("oracle".equals(dbType)) {
- SqlInfo sqlInfo = readSQL4SQLServer(sql);
- newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
- .replace(startMark, Integer.toString(fromIndex+1))
- .replace(endMark, Integer.toString(toIndex));
- }else if ("mysql".equals(dbType)) {
- SqlInfo sqlInfo = readSQL4Hive(sql);
- newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
- .replace(startMark, Integer.toString(fromIndex))
- .replace(endMark, Integer.toString(pageSize));
- }else if ("sqlserver".equals(dbType)) {
- SqlInfo sqlInfo = readSQL4SQLServer(sql);
- newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
- .replace(startMark, Integer.toString(fromIndex+1))
- .replace(endMark, Integer.toString(toIndex))
- .replace(orderMark, "(SELECT 1)");
- }else if ("hive".equalsIgnoreCase(dbType)){
- //hive的话 目前单表查询采用的是一种偷懒的方法,拆分sql获取字段名和表名
- SqlInfo sqlInfo = readSQL4Hive(sql);
- newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
- .replace(startMark, Integer.toString(fromIndex))
- .replace(endMark, Integer.toString(toIndex+1))
- .replace(orderMark, sqlInfo.getFirstColumn());
- }
-
- List<Map<String,Object>> select = xxxService.select(dbId, newSQL);
-
- map.put("list", select);
- return map;
- }

关于第一个参数:dbId,是存在数据库的相关数据源的主键值,可以理解为要操作的数据源的一些基本信息,后续不再说明。其他的几个参数:要分页的sql语句,当前页码数,分页大小,是否进行分页。
总的来说,此方法就是根据不同的数据源类型生成不同的分页sql,然后交给数据库去执行,然后返回统一格式的数据,供前端使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。