首页 > 其他分享 >PageHelper 使用 ThreadLocal 的线程复用问题,你用对了吗?(转载)

PageHelper 使用 ThreadLocal 的线程复用问题,你用对了吗?(转载)

时间:2023-03-20 09:35:37浏览次数:34  
标签:remove PAGE ThreadLocal 参数 线程 PageHelper LOCAL page

前言

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

简单的 分页执行过程:

  1. 设置 page 参数
  2. 执行 query 方法
  3. Interceptor 接口 中校验 ThreadLocal 中是否存在有设置的 page 参数
  4. 存在 page 参数,重新生成 count sqlpage sql,并执行查询。不存在 page 参数,直接返回 查询结果
  5. 执行 LOCAL_PAGE.remove()清除 page 参数

问题场景

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

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

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

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());
    }
}

 

转载于:https://cloud.tencent.com/developer/article/1950579

标签:remove,PAGE,ThreadLocal,参数,线程,PageHelper,LOCAL,page
From: https://www.cnblogs.com/grassLittle/p/17235195.html

相关文章

  • Python 多进程、多线程对比(转载)
    https://www.runoob.com/w3cnote/python-single-thread-multi-thread-and-multi-process.html具体实验见原文,这里只是引用实验结果,方便查询......
  • php线程安全(TS)和非线程(NTS)安全区别 本文来源:码农网 本文链接:https://www.coderct
    以下线程安全简称TS非线程安全简称NTS首先unix/linux不强调使用线程模型,强调使用多进程模型,windows下面才强调使用多线程。创建进程的速度比创建线程慢几倍,并且相互通信......
  • 多线程
    多线程线程的创建Thread类自定义线程类继承Thread类重写run()方法,编写线程执行体创建线程对象,调用start()方法启动线程publicclassDemo01extendsThread{p......
  • Java多线程开发CompletableFuture的应用
    ​做Java编程,难免会遇到多线程的开发,但是JDK8这个CompletableFuture类很多开发者目前还没听说过,但是这个类实在是太好用了,了解它的一些用法后相信你会对它爱不释手(呸渣男,......
  • 线程池
    packageedu.wtbu;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassDemo04{publicstaticvoidmain(String[]a......
  • 外界参数控制多线程队列进行与否
    业务场景,最近遇到个需求,就是通过点击开始/继续要控制任务进度,刚开始想到了线程wait,notify本人是个比较懒得人,一想到要写那么多代码空值,要等待,唤醒,睡眠啥的就觉得麻烦,出......
  • 13 中断线程
    代码1概述避免workqueue中存在多个work会导致后面的work执行存在受前面工作的影响在中断下半部专门申请一个内核线程来处理这个事件,这个内核线程专门用于此中断1.1内......
  • 温习:进程和线程的区别
    进程和线程的区别:1、定义不一样,进程是执行中的一段程序,线程是进程里执行中的任务,一个进程里可以有多个线程。2、一个线程只能属于一个进程。3、线程无地址空间,它包括在......
  • CAS 是一种什么样的同步机制?多线程下为什么不使用 int 而使用 AtomicInteger?
    CompareAndSwap,比较交换。可以看到synchronized可以保证代码块原子性,很多时候会引起性能问题,volatile也是个不错的选择,但是volatile不能保证原子性,只能在某些场合下使......
  • 关于java.lang.ThreadDeath线程发生场景及模拟代码测试
    当调用stop()方法时会发生两件事:1.即刻停止run()方法中剩余的全部工作,包括在catch或finally语句中,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导......