【260期】PageHelper 使用 ThreadLocal 的线程复用问题,你用对了吗?

点击上方“Java精选”,选择“设为星标”

别问别人为什么,多问自己凭什么!

下方有惊喜,留言必回,有问必答!

每一天进步一点点,是成功的开始...

245730251d0bd5e8ab6ec46f315bd9ac.png

前言

PageHelper是较为常用的分页插件,通过实现Mybatis的Interceptor接口完成对query sql的动态分页,其中分页参数由ThreadLocal进行保存。

简单的 分页执行过程:

  1. 设置page参数

  2. 执行query方法

  3. Interceptor接口 中校验ThreadLocal中是否存在有设置的page参数

  4. 存在page参数,重新生成 count sql 和 page sql,并执行查询。不存在 page参数,直接返回 查询结果

  5. 执行 LOCAL_PAGE.remove()清除page参数

问题场景

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

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

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

推荐下自己做的 Spring boot 的实战项目:
https://gitee.com/yoodb/jing-xuan‍

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

解决方案

因为Tomcat的线程是用来处理request请求,那么在请求完成时,清空当前线程的threadLocals 属性值,也就是执行 LOCAL_PAGE.remove() 即可。实现方式:

  • 使用aop,对所有controller进行处理

  • 实现 HandlerInterceptor 或者 WebRequestInterceptor 对request请求的拦截器接口,通过afterCompletion方法执行 LOCAL_PAGE.remove()。— 推荐,实现方式简单

这里使用第二种方式,实现 HandlerInterceptor 接口:

public class PageLocalWebInterceptor implements HandlerInterceptor {
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // PageHelper.clearPage() 内部调用 LOCAL_PAGE.remove()
        PageHelper.clearPage();

    }
}

定义配置类,配置类需实现 WebMvcConfigurer 接口完成对于WebMvc的相关配置 ,注册 PageLocalWebInterceptor :

@Configuration
public class FrameworkAutoConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PageLocalWebInterceptor());
    }
}

版权声明:本文为CSDN博主「方片龙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

https://blog.csdn.net/qq_38245668/article/details/105984171

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

------ THE END ------

6f8ed08533b970cb15b99551ab531e6c.png精品资料,超赞福利!4605841b8a10fc2c6fdec079d777a652.png

>Java精选面试题<
3000+ 道面试题在线刷,最新、最全 Java 面试题!

6d796ce1f45b6ab8426c28df4ade2722.png

52209ce93e480351265306f71a78a1bb.png

期往精选  点击标题可跳转

【252期】爆赞,对 volatile 关键字讲解最好的一篇文章!

【253期】京东二面:商品库存的扣除过程中,如何防止超卖问题?

【254期】这些 SQL 语句真是让我干瞪眼!

【255期】面试官问:MyBatis 二级缓存,如何实现关联刷新功能?

【256期】MySQL 中 varchar 最大长度?char 和 varchar 有什么区别?

【257期】Java8 的 Stream 不好调试?试试 IDEA StreamTrace!

【258期】如何利用自定义注解放行 Spring Security项目的接口?

【259期】揭秘 MySQL 中 count 是怎样执行的?

136c03a2b0c20215b7a91ce71baebd06.png 技术交流群!e81782a57e53d8489c30587e41e68d47.png

最近有很多人问,有没有读者交流群!想知道如何加入?方式很简单,兴趣相投的朋友,只需要点击下方卡片,回复“加群”,即可无套路入交流群!

文章有帮助的话,在看,转发吧!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值