当前位置:   article > 正文

不再东寻西找,常见数据库分页方法都在这里了

数据库分页

       在日常的开发中,做数据分页是很常见的需求了,面对各种各样的数据库或者是多数据源,有没有一种可以共用的实现方法呢,在明确数据量不大的情况下,逻辑分页不失为一种快速通用的方法,因为无须对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

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

       以上就是核心内容,下面来一个具体案例,一个通用的sql查询分页方法:

  1. private Map<String,Object> startPage4Preview(String dbId, String sql, int pageIndex, int pageSize,Boolean noPagination) throws BusinessException, SQLException, RucException, IOException {
  2. Map<String, String> dbs = new HashMap<>();
  3. String sqlMark = "#SQL";
  4. String startMark = "#START_COUNT";
  5. String endMark = "#END_COUNT";
  6. String orderMark = "#ORDER";
  7. String columnNames = "#COLUMN_NAMES";
  8. dbs.put("oracle", "SELECT #COLUMN_NAMES FROM (SELECT A.*,ROWNUM RN FROM (#SQL) A WHERE ROWNUM <=#END_COUNT) WHERE RN >=#START_COUNT");
  9. dbs.put("mysql", "select #COLUMN_NAMES from (#SQL) A limit #START_COUNT,#END_COUNT");
  10. 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");
  11. 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");
  12. boolean isFirstPage=false;
  13. boolean isLastPage=false;
  14. boolean haveNexPage=false;
  15. boolean havePerPage=false;
  16. Integer totalPage;
  17. //获取查询到的总行数
  18. int totalRow=getSqlCounts(dbId, sql);
  19. if (noPagination!=null&&noPagination&&totalRow>0){
  20. pageSize = totalRow;
  21. }
  22. int fromIndex=(pageIndex-1)*pageSize;
  23. int toIndex=pageIndex*pageSize;
  24. if(fromIndex==0) {
  25. isFirstPage=true;
  26. }else {
  27. havePerPage=true;
  28. }
  29. if(toIndex>=totalRow) {
  30. toIndex=totalRow;
  31. isLastPage=true;
  32. }else if (!isLastPage) {
  33. haveNexPage=true;
  34. }
  35. if(totalRow%pageSize==0) {
  36. totalPage=totalRow/pageSize;
  37. }else {
  38. totalPage=totalRow/pageSize+1;
  39. }
  40. Map<String,Object> map=new HashMap<>();
  41. map.put("pageIndex", pageIndex);
  42. map.put("totalPage", totalPage);
  43. map.put("totalCount", totalRow);
  44. map.put("pageSize", pageSize);
  45. map.put("firstPage", isFirstPage);
  46. map.put("lastPage", isLastPage);
  47. map.put("haveNexPage", haveNexPage);
  48. map.put("havePerPage", havePerPage);
  49. String dbType = getConnectionType(dbId);
  50. String newSQL = dbs.get(dbType).replace(sqlMark, sql);
  51. if("oracle".equals(dbType)) {
  52. SqlInfo sqlInfo = readSQL4SQLServer(sql);
  53. newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
  54. .replace(startMark, Integer.toString(fromIndex+1))
  55. .replace(endMark, Integer.toString(toIndex));
  56. }else if ("mysql".equals(dbType)) {
  57. SqlInfo sqlInfo = readSQL4Hive(sql);
  58. newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
  59. .replace(startMark, Integer.toString(fromIndex))
  60. .replace(endMark, Integer.toString(pageSize));
  61. }else if ("sqlserver".equals(dbType)) {
  62. SqlInfo sqlInfo = readSQL4SQLServer(sql);
  63. newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
  64. .replace(startMark, Integer.toString(fromIndex+1))
  65. .replace(endMark, Integer.toString(toIndex))
  66. .replace(orderMark, "(SELECT 1)");
  67. }else if ("hive".equalsIgnoreCase(dbType)){
  68. //hive的话 目前单表查询采用的是一种偷懒的方法,拆分sql获取字段名和表名
  69. SqlInfo sqlInfo = readSQL4Hive(sql);
  70. newSQL = newSQL.replace(columnNames,sqlInfo.getColumns())
  71. .replace(startMark, Integer.toString(fromIndex))
  72. .replace(endMark, Integer.toString(toIndex+1))
  73. .replace(orderMark, sqlInfo.getFirstColumn());
  74. }
  75. List<Map<String,Object>> select = xxxService.select(dbId, newSQL);
  76. map.put("list", select);
  77. return map;
  78. }

       关于第一个参数:dbId,是存在数据库的相关数据源的主键值,可以理解为要操作的数据源的一些基本信息,后续不再说明。其他的几个参数:要分页的sql语句,当前页码数,分页大小,是否进行分页。

       总的来说,此方法就是根据不同的数据源类型生成不同的分页sql,然后交给数据库去执行,然后返回统一格式的数据,供前端使用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/48986
推荐阅读
相关标签
  

闽ICP备14008679号