前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Springboot引入pageHelper流程以及小坑

Springboot引入pageHelper流程以及小坑

作者头像
名字是乱打的
发布2021-12-24 09:16:53
1.6K0
发布2021-12-24 09:16:53
举报
文章被收录于专栏:软件工程
mybatisPlus使用分页插件pagehelper

mybatisplus自带的插件一般用于我们使用其自带的sql操作api,比如查询的时候加一个ipage,这一般不适用于我们自己写的sql操作,想应用于自定义sql比较麻烦,这里介绍一款我们mybatis和mybatisplus都可以使用的分页插件pagehelper mybatis引用

代码语言:javascript
复制
  <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper</artifactId>
                <version>5.2.0</version>
            </dependency>

springboot項目引用

代码语言:javascript
复制
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>1.2.13</version>
            </dependency>

pagehelper的相關配置

代码语言:javascript
复制
pagehelper.helper-dialect=mysql
pagehelper.reasonable=false
pagehelper.support-methods-arguments=true
pagehelper.offset-as-page-num=true
pagehelper.row-bounds-with-count=true
pagehelper.propertyName=propertyValue

关于各个属性的相关含义可以看其官方文档mp参数配置

使用方法
代码语言:javascript
复制
@Test
    public void test() {
        PageHelper.startPage(1, 2);
        List<User> users = userService.queryAll(new User());
        PageInfo<User> pageInfo = new PageInfo<>(users);
        PageHelper.clearPage();
        List<User> list = pageInfo.getList();
        list.forEach(System.out::println);
    }

非常简单,我们仅需要在调用查询的方法前后加上分页语句即可,其中 PageHelper.startPage(1, 2);表明开始使用分页查询,查第一页,两条数据。 但是这里要注意我们必须夹紧中间sql业务,也就说两个pagehelper语句直接不能有空行,且中间的语句是直接操作数据库的,不含有其他业务操作,所以我们一般会把这些分页操作写在dao层或者service层。

注意了,这里用了pagehelper.clearPage()是干啥的?

PageHelper 是较为常用的分页插件,通过实现 Mybatis 的 Interceptor 接口完成对 query sql 的动态分页,其中分页参数由 ThreadLocal进行保存,threadlocal而是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据.

简单的 分页执行过程:
  • 1.设置 page 参数
  • 2.执行 query 方法
  • 3.Interceptor 接口 中校验 ThreadLocal 中是否存在有设置的 page 参数
  • 4.存在 page 参数,重新生成 count sql 和 page sql,并执行查询。不存在 page 参数,直接返回 查询结果
  • 5.执行 LOCAL_PAGE.remove() 清除 page 参数 threadlocal
这里就存在一个问题了

观察上述的执行过程,可以发现,如果在第 1 步和第 2 步 之间发生异常,那么 LOCAL_PAGE 中当前线程对应的 page 参数并不会 remove。

在不使用线程池的情况下,当前线程在执行完毕后会被销毁,这时 当前线程 中的 threadLocals 参数 将会被情况,也就清空 了 LOCAL_PAGE 中 当前线程的 page 参数。

但是如果使用了线程池,当前线程执行完毕,并不会被销毁,而是会将当前线程再次存放到池中,标记为空闲状态,以便后续使用。在后续使用这个线程的时候,由于 线程 的 threadLocals 依旧存在有值,尽管我们在第 1 步时未设置 page 参数,第 3 步 的也能获取到page参数,从而生成 count sql 和 page sql,从而影响我们的正常查询我。

另外SpringBoot 项目中会使用内置的 Tomcat 作为服务器,而Tomcat会默认使用线程来处理请求,从而便引发了上述问题

解决方案,在每次使用完分页语句后执行pagehelper.clearpage()如上demo所示,但是这样比较麻烦

我们可以实现 HandlerInterceptor , WebRequestInterceptor 对 request 请求的拦截器,q清理我们localthread里的page

代码语言:javascript
复制
@Component
public class UrlInterceptor implements HandlerInterceptor, WebMvcConfigurer {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        PageHelper.clearPage();
        return true;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this).addPathPatterns("/**");
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/6/22 上,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • mybatisPlus使用分页插件pagehelper
  • 使用方法
  • 注意了,这里用了pagehelper.clearPage()是干啥的?
    • 这里就存在一个问题了
    • 解决方案,在每次使用完分页语句后执行pagehelper.clearpage()如上demo所示,但是这样比较麻烦
    相关产品与服务
    数据保险箱
    数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档