统一业务场景的查询,有时候会全量查询和分页查询都需要的情况。一般情况下,会让一个类提供两个方法,一个完成全量查询,一个完成分页查询。比如这样:
1. 全量查询方法: list query(Conditon condition);
2. 分页查询方法:list query(Condition condition, int pageNum, int pageSize);

一个方法实现分页查询和全量查询

上文已经提到只提供全量查询的服务,扩展不出物理分页的查询功能。那么只提供分页查询方法,能够实现出全量查询的功能吗?回答是肯定的。

比如只有list query(Condition condition, int pageNum, int pageSize),怎么能够全量查询呢?有两种方法:
1. 方法一:分页方法只需实现分页逻辑即可:我们可以pageNum传1,pageSizeInteger.MAX_VALUE。这么做对数据和方法是有要求的,所以是有风险的。
- 数据:数据的总条数不能多于Integer.MAX_VALUE
- 方法:不能对pageSize大小有限制
2. 方法二:我们知道正常逻辑下,pageNumpageSize不能小于1,那么可以约定,当传参pageNumpageSize有一个小于1时,就做全量查询,否则就做分页查询。相当于,我们把全量查询方法和分页查询方法合二为一了,一个方法实现两套逻辑,好处是没有风险。(也可以把pageNumpageSize都使用包装类Integer,当有一个为null时做全量查询,道理是一样的)

方法一是有风险的,方法二是在一个方法即实现了全量又实现了分页。以上方法都是对pageNumpageSize传参做要求,当满足条件时,就是全量查询。总之我们能够做到一个方法既能全量,又能分页。下文我们称这类方法为合二为一

合二为一的优势分析

下面分别从方法定义方和方法使用方说说其优势:
1. 定义方:如果采用的是方法一,只需实现分页逻辑即可,因为其把(pageNum=1,pageSize=Integer.MAX_VALUE)的分页查询视作是全量查询
2. 使用方:全量和分页,只需要熟悉一个方法的使用就行了

合二为一的劣势分析

下面分别从方法定义方和方法使用方说说其劣处:
1. 定义方
根据单一职责原则,一个函数只做一件事且做好这件事。这里,其实违背了单一职责原则。
1. 采用方法一:
要求数据的总条数不能多于Integer.MAX_VALUE,不能对pageSize大小有限制。
2. 采用方法二:
一个方法需要针对参数不同实现两套逻辑,混杂在一起容易混乱。
p.s. 当然内部可以使用Extract Method重构手法,将分页和全量抽取不同的私有方法,降低复杂度。然而这已经违背我们初衷了,初衷是想一个方法提供两种服务,但其实您却在内部已经实现了两种查询服务,却不开放。
2. 使用方
全量和分页,虽然只需要熟悉一个方法的使用就行了,但这个方法是复杂的,不易使用的。理由如下
1. 两个方法,就是二选一,全量就用A,分页就用B;
合二为一,通过参数来区分,理论上,int的可能取值有Integer.MAX_VALUE - Integer.MIN_VALUE + 1
pageNumpageSize加起来的取值就有(Integer.MAX_VALUE - Integer.MIN_VALUE + 1) * (Integer.MAX_VALUE - Integer.MIN_VALUE + 1) = 18446744073709551616种可能性,我们必须使用文档约束哪些可能性是用于全量查询的。对于使用方来说,他需要查看文档说明,才知道究竟怎么传参才是全量查询。而且这种约束不是强制性的,好比我现在是要做全量查询的,本该传(-1, -1)的,却不经意写成了(1, 1),然而写错了编译也不报错,使用不到编译器强制保证提前报错的好处 ;运行时也不会出错,因为其能返回一页的数据(用户可能会误以为,这一页的数据就已经是全部的数据了)。(如果是使用包装类Integer,可能性就更多了)
2. 再看一下调用方式
“`java
//第一种方法
query(condition, 1, Integer.MAX_VALUE);
//第二种方法
query(condition, -1, -1);
query(condition, null, null);

    //如果不合二为一,多定义一个全量查询方法query(condition);//或queryAll(condition);```只看代码:第一种方法还更好一点,但是也需要想一会儿,才领会到该使用方大概是想获取全量数据的吧?然而该方法支持一次获取这么大量吗?总数据量超过了`Integer.MAX_VALUE`呢?第二种方式的调用,我们完全看不出使用方是在做一次全量查询,而且这种调用方式好像是在故意使坏,好像是试图诱发程序的bug,因为明明第-1页每页-1条的数据页根本就不存在,`null`就更离谱了。我们看`query(conditon)`,它除了`conditon`没有更多的参数,没有分页参数传入,我们就会想这应该是做全量查询的吧?如果方法名明确使用`queryAll`就更加明晰了,我们就有更大的把握,这是在做一次全量查询的。如果方法名是`queryAll`,却做了返回部分数据的事,那方法就名不副实了,这是定义方的错误,要极力避免的。
3. 再看以下方法调用,这里我们使用传`null`代表全量```java@RestControllerpublic class Controller {@Autowiredprivate Service service;@GetMapping(path="/getAll")public List<Model> getAll(@ModelAttribute Condition condition) {return service.query(condition, null, null);}}@Servicepublic class Service {@Autowiredprivate Dao dao;public List<Model> query(Condition condition, Integer pageNum, Integer pageSize) {...dao.query(condition, pageNum, pageSize);...}}@Repositorypublic class Dao {// 合二为一public List<Model> query(Condition condition, Integer pageNum, Integer pageSize) {if (pageNum == null || pageSize == null) {//全量} else {//分页}}}````Service.query()`是合二为一的,`Dao.query()`也是合二为一的,`Service.query()`只是调用`Dao.query()`实现自己的合二为一逻辑。这里只有两层这种调用,但可以想象,如果都采用合二为一,实际开发中,可能会有好多层。我们只看中间层,比如在这里,`Service.query()`中对`Dao.query()`的调用,我们就不明确调用的意图是分页还是全量,得向前追查。实参的定义与真正要用参数的最底层`query()`也隔开了距离,为了调试全量查询的bug,我们得往前查找,看究竟是哪层的调用出现了传参错误。&emsp;如果两个方法,一个全量,一个分页呢:```java@RestControllerpublic class Controller {@Autowiredprivate Service service;@GetMapping(path="/getAll")public List<Model> getAll(@ModelAttribute Condition condition) {return service.queryAll(condition);}}@Servicepublic class Service {@Autowiredprivate Dao dao;//分页public List<Model> queryPage(Condition condition, Integer pageNum, Integer pageSize) {...dao.queryPage(condition, pageNum, pageSize);...}//全量public List<Model> queryAll(Condition condition) {...dao.queryAll(condition);...}}@Repositorypublic class Dao {//分页public List<Model> queryPage(Condition condition, Integer pageNum, Integer pageSize) {}//全量public List<Model> queryAll(Condition condition) {}}```再看这里的中间层,是不是就很明晰了呢?

推荐

定义一个方法就是为了使用的,优劣更应该考虑的是使用方的感受。阅读代码的时间也远比写代码的时间更多。个人觉得,定义两个方法(一个全量,一个分页),然后再加上使用语义清晰的方法名,是值得的,整体上优于只用一个方法既能全量又能分页的。

实际上很多jdk源码或开源源码都做了完成类似功能定义多个方法的做法。这里举两个jdk中的例子:

// 虽然只是简单调用另一个wait,但是定义了一个新的wait
public class Object {/*** 一直等待*/public final void wait() throws InterruptedException {wait(0);}/*** 等待tomeout时间,如果超时,不再等待。如果timeout为0,一直等待*/public final native void wait(long timeout) throws InterruptedException;
}// 虽然只是简单调用另一个parseInt,但是定义了一个新的parseInt
public class Integer {/*** 转换10进制*/public static int parseInt(String s) throws NumberFormatException {return parseInt(s,10);}/*** 指定进制转换*/public static int parseInt(String s, int radix) {...}
}

如果jdk不提供不带参wait()方法,我们的所有代码都需要使用wait(0)这样调用。如果确定就是永久等待,调用wait(0)虽然实现了相同的功能,但比wait()却让我们脑子先转一个弯,去想参数的意义。

虽然jdk增加了不带参的wait()parseInt方法,增多了jdk的代码量,但我们使用者使用的时候是减少了我们代码量,因为不用传参了。

当然,带来的好处,更多的比代码量要重要的多。比如parseInt, 虽说jdk既有parseInt(String s)又有parseInt(String s, int radix)。如果您更喜欢更加通用的带参的parseInt(String s, int radix)的方法,即使是10进制格式String转int时,完全可以忽视parseInt(String s),每次这样调用:

Integer.parseInt("17895341", 10)`;
Integer.parseInt("45612", 10)`;

然而,针对大多数情况下String转int时radix都是10的这种事实,jdk还是定义了不带radix参数(默认是10)的int parseInt(String s)方法,把更通用的int parseInt(String s, int radix)反而作为了例外
参数少总是好于参数多,如果不仅多还是同一类型的就更加讨厌。比如query(2, 5, 6, 1, 6)

全量查询与分页查询合二为一的思考相关推荐

  1. html 分页_MySQL——优化嵌套查询和分页查询

    Java识堂,一个高原创,高收藏,有干货的微信公众号,欢迎关注 优化嵌套查询 嵌套查询(子查询)可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中.嵌套查询写 ...

  2. SQL条件查询,分组查询,排序查询,分页查询

    DQL查询操作(条件查询,分组查询,排序查询,分页查询) 文章目录 DQL查询操作(条件查询,分组查询,排序查询,分页查询) 一.查询语法 二.基础查询 三.条件查询 四.排序查询 五.分组查询 六. ...

  3. SQL分组查询和分页查询[代码+运行结果+讲解]

    文章目录 前言 一.分组查询 二.分页查询 总结 前言 分组查询和分页查询也是开发中用到的对数据库表的查询操作.下述代码都是通过stu表,内容如下图: 一.分组查询         1.查询男同学和女 ...

  4. oracle数据库同时实现联表查询和分页查询(未明确定义列)

    ps:只是记录新手小白的脱坑之路,大佬勿喷 今天在做前端数据查询的时候,在实现联表查询的同时进行分页查询遇到了令人头秃的问题,分页查询的sql语句是这样的 select * from (select ...

  5. Mysql进阶学习(六)子查询与分页查询

    Mysql进阶学习(六)子查询与分页查询 进阶7:子查询 1.含义: 2.分类: 3.where或having后面 3.1 特点: 3.2.标量子查询★ 案例1:谁的工资比 Abel 高? 案例2:返 ...

  6. Oracle篇--04 Oracle SQL高级查询、分页查询

    1.子查询 子查询是一条SELECT语句,但它是嵌套在其他SQL语句中的,为的是给该SQL提供数据以支持其执行操作. 查看谁的工资高于CLARK?select ename,sal from emp w ...

  7. python分页查询_分页查询

    分页 使用SELECT查询时,如果结果集数据量很大,比如几万行数据,放在一个页面显示的话数据量太大,不如分页显示,每次显示100条. 要实现分页功能,实际上就是从结果集中显示第1~100条记录作为第1 ...

  8. MySQL——分组查询和分页查询

    分组查询:group by 格式: select 聚合函数(列名)from 表名[where条件] group by 列名 [having 条件]; 面试会问:where子句和having子句的区别? ...

  9. selec查询、分页查询及优化

    1. select查询 select _column,_column from _table [where Clause] [limit N][offset M] 解析:LIMIT 子句可以被用于强制 ...

  10. 商城后台管理系统之普通查询_分页查询_商品的添加,单个删除,批量删除

    一.MVC开发模式和JavaEE经典三层结构 1.JSP开发模式一: jsp(接收请求,响应请求,展示数据)+javabean(处理业务逻辑) javaBean:可复用的java组件 -user -u ...

最新文章

  1. MonoScene: 单目3D语义场景补全
  2. android 桌面提醒功能,安卓手机桌面上使用的工作提醒软件选择哪个?
  3. 如何应用Java的BigDecimal类
  4. python os.path模块学习(转)
  5. C# 使用Linq递归查询数据库遇到的问题及解决方法
  6. PMP-【第1章 引论】-2020-12-29(25页-34页)
  7. 加密算法、DES、IDEA、RSA、DSA
  8. 【白话机器学习】算法理论+实战之K近邻算法
  9. zShowBox (图片放大展示jquery版 兼容性好)
  10. 转: Div与table的区别
  11. Leetcode883.Projection Area of 3D Shapes三维形体投影面积
  12. Jrebel激活方法
  13. 解决IE8不能安装支付宝控件问题
  14. axis1 创建service服务端 , axis1 客户端
  15. 《Android游戏编程入门经典》——14.4节问与答
  16. MySQL表中部分字段生成视图_MySQL学习笔记之视图
  17. hexo theme next7.8 主题美化
  18. openwrt路由器打印机服务器设置_openwrt 路由器下HP 打印机的安装
  19. 在微博投放广告有哪些优势呢?微博广告推广位置介绍!
  20. 个人微信支付接口,非二清,无需APP,支持H5

热门文章

  1. 团队协作工具,如何加强团队协作能力
  2. linux英文论文范例,Argument essay官方主题范文三十六篇-经典英文议论文范例
  3. c语言程序填空 功能:输出结果为:,C语言程序填空题
  4. vba 更新mysql数据库_使用VBA中的UPDATE SQL语句更新Access数据库
  5. 皮德常《c++程序设计教程》第一章第二题:编写一个程序,要求用户输入一年12个月每月的降雨总数,并用一个float数组存储。
  6. 初步了解FPGA中的HLS
  7. gpio_set_value 函数
  8. 句子反转(小米2016年笔试题)
  9. HTML页面嵌入视频无法播放的常见原因
  10. 淘宝在线客服为什么回复那么慢