数据分页分析

【数据分页】

比较朴素的做法

前端发送请求分页的必要数据

{
    pageNum: 1,
    pageSize: 10,
}

后端接收这几个参数

public class Param {
    // 其他参数
    // ...
    private Integer pageNum;
    private Integer pageSize;
}

这里有什么问题呢?

  1. 每个 需要分页操作的参数,需要有 pageNum pageSize 这些参数;
  2. 每个 需要分页的操作,需要在 sql 中手动显式拼接 LIMIT 之类的分页操作。

参数类里的 page 相关参数拆分

比较朴素的做法是把分页的数据抽出来一个父类,用 Param 继承 BasePage 类,如下:

public class BasePage {
    private Integer pageNum;
    private Integer pageSize;
}

public class Param extends BasePage {
    // 业务参数
    // ...
}

这样只是把写在 Param 里的分页参数,换了个地方,实际还是对于业务的一个强侵入,比如当 Param 需要继承一个比 BasePage 重要程度要高的业务相关类的时候,因为 Java 的单继承机制,分页参数的去向又需要某些迂回操作了。

另一种方式是直接从 HttpRequest 里往外拿值,让业务的 Param 对分页操作无感知。

pubic class Param { // 没有继承 BasePage
    // 业务参数
    // ...
}

public calss Page {
    private Integer pageNum;
    private Integer pageSize;
}

public static Page getPage(HttpRequest request) {
    Integer pageNum = request.getParam("pageNum");
    Integer pageSize = request.getParam("pageSize");

    return new Page(pageNum, pageSize);
}

看到这里,业务参数和分页参数就已经分开了,但还没显现出优势,比如你可能会问,这样往后传递参数的时候,不还多了一个 Page 类型的参数么?从参数的强耦合,变成了接口传参的强耦合了。

// 原有的
List<Result> selectList(Param param);

// 改完的
List<Result> selectList(Param param, Page page);

这样不是更大的麻烦了吗?

解决一个问题,引入另一个问题,扯淡了。。。

莫慌,有解决方法,ThreadLocal 线程共享变量,从 HttpRequest 中拿到 Page 相关的参数之后,不往后传,而是存到 ThreadLocal 中,当有需要的时候再去拿,如下:

public class PageHolder {
    private static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();

    public static void setPage(Page page) {
        LOCAL_PAGE.set(page);
    }

    public static Page getPage() {
        return LOCAL_PAGE.get();
    }

    public static void clearPage() {
        LOCAL_PAGE.remove();
    }
}

// 保持原有接口不变
List<Result> selectList(Param param);

那什么时候需要去拿那个参数呢?执行 SQL 之前。

拼接 SQL

PageHolder 中拿到 Page 相关的参数之后,根据具体的数据库类型,在 SQL 上拼接上分页需要的操作,比如 mysql 的 limit

这里面需要解决什么问题呢?

如果自己写 sql 的时候不去写 limit 而让程序自己去拼接,则需要 拦截 执行 sql 的操作(比如这里的 selectList(Param param))拿到要执行的 sql 语句,怎么做呢?

在 Mybatis 中的 org.apache.ibatis.plugin 中的 InterceptsInterceptor 允许定义自己的拦截器,在自定义实现中,就可以在 sql 上拼接上 limit 并把 PageHolder 中的 Page 相关参数设置进去。

至此就可以做到业务无侵入的分页了。

注意: ThreadLocal 的值用完以后,记得在 finally 块remove(),避免内存泄漏。

总结

  1. 从 HttpReuqest 中直接拿 Page 相关参数
  2. 使用 ThreadLocal 存储 Page 参数
  3. 自定义拦截器,拼接 limit + Page 相关参数

原理大概就是这样了,而且也不需要自己再去造轮子了,有成熟的库可用

MyBatis 分页插件 PageHelper

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lixifun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值