PageHelper引发的幽灵数据问题解析

目录
  • 前言
  • 大胆猜测
  • PageHelper工作原理
  • Tomcat请求流程
  • 总结

前言

最近测试反馈一个问题,某个查询全量信息的接口,有时候返回全量数据,符合预期,但是偶尔又只返回1条数据,简直就是“见鬼”了,究竟是为什么出现这样的“幽灵数据”呢?

大胆猜测

首先我们看了下这对代码的业务逻辑,非常的简单,总共没有几行代码,也没有分页逻辑,代码如下:

public  List<SdSubscription> findAll() {
    return sdSubscriptionMapper.selectAll();
}

那么究竟是咋回事呢?讲道理不可能出现这种情况的啊,不要慌,我们加点日志,将日志级别调整为DEBUG,让日志飞一段时间。

public  List<SdSubscription> findAll() {
    log.info("find the sub start .....");
    List<SdSubscription> subs = sdSubscriptionMapper.selectAll();
     log.info("find the sub end .....");
    return subs;
}

果不其然,日志中出现了奇奇怪怪的分页参数,如下图所示:

果然是PageHelper这个开源框架搞的鬼,我想大家都用过吧,分页非常方便,那么究竟为什么别人都没问题,单单就我会出现问题呢?

PageHelper工作原理

为了回答上面的疑问,我们先看看PageHelper框架的工作原理吧。

PageHelper 是一个开源的 MyBatis 分页插件,它可以帮助开发者在查询数据时,快速的实现分页功能。

PageHelper 的工作原理可以简单概括为以下几个步骤:

  • 在需要进行分页的查询方法前,调用 PageHelper 的静态方法 startPage(),设置当前页码和每页显示的记录数。它会将分页信息放到线程的ThreadLocal中,那么在线程的任何地方都可以访问了。
  • 当查询方法执行时,PageHelper 会自动拦截查询语句,如果发现线程的ThreadLocal中有分页信息,那么就会在其前后添加分页语句,例如 MySQL 中的 LIMIT 语句。
  • 查询结果将被包装在 Page 对象中返回,该对象包含分页信息和查询结果列表。
  • 在查询方法执行完毕后,会在finally中清除线程ThreadLocal中的分页信息,避免分页设置对其他查询方法的影响。

PageHelper 的实现原理主要依赖于拦截器技术和反射机制,通过拦截查询语句并动态生成分页语句,实现了简单、高效、通用的分页功能。具体源码在下图的类中,非常容易看懂。

明白了PageHelper的工作原理后,反复检查代码,都没有调用过startPagedebug查看ThreadLocal中也没有分页信息啊,懵逼中。那我看看别人写的添加分页参数的代码吧,不看不知道,一看吓一跳。

原来有位“可爱”的同事竟然在查询后,加了一个分页,就是把分页信息放到线程的ThreadLocal中。

那大家是不是有疑问,丁是丁,矛是矛,你的线程关我何事?这就要说到我们的tomcat了。

Tomcat请求流程

其实这就涉及到我们的tomcat相关知识了,我们一个浏览器发一个接口请求,经过我们的tomcat的,究竟是一个什么样的流程呢?

  • 客户端发送HTTP请求到Tomcat服务器。
  • TomcatHTTP连接器(Connector)接收到请求,将连接请求交给线程池Executor处理,解析它,然后将请求转发给对应的Web应用程序。
  • Tomcat的Web应用程序容器(Container)接收到请求,根据请求的URL找到对应的Servlet

关于tomcat中使用线程池提交浏览器的连接请求的源码如下:

从而得知,你的连接请求是从线程池从拿的,而拿到的这个线程恰好是一个“脏线程”,在ThreadLocal中放了分页信息,导致你这边出现问题。

总结

后来追问了同事具体原因,才发现是粗心导致的。有些bug总是出现的莫名其妙,就像生活一样。所以关键的是我们在使用一些开源框架的时候一定要掌握底层实现的原理、核心的机制,这样才能够在解决一些问题的时候有据可循。

以上就是PageHelper引发的幽灵数据问题解析的详细内容,更多关于PageHelper幽灵数据的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring 中 PageHelper 不生效问题及解决方法

    使用这个插件时要注意版本的问题,不同的版本可能 PageHelper 不会生效 springboot 导入的 pagehelper 包 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.6</version> </depen

  • PageHelper在springboot+mybatis框架中的使用步骤及原理解析

    目录 一.思路 二.主要逻辑 三.步骤 一.思路 将分页所需的内容都放到一个实体类中 分页数据所需要的实体类!内包含页码,页大小,总条数,总页数,起始行 pagehelpr提供了这个类 pageInfo,不需要我们自己创建 二.主要逻辑 select * from 表名 limit 起始行,展示几条数据 #第n页 每页展示五条数据 select * from 表名 limit (n-1)*5,5 #每页展示多少条 pageSize 3 #总共有多少条 total select count(*)

  • 解决pageHelper分页失效以及如何配置问题

    目录 pageHelper分页失效及配置问题 原因 解决方案 PageHelper分页无效及报错 第一种情况SQL报错 第二种情况分页无效 总结 pageHelper分页失效及配置问题 我在使用pageHelper的系统中加入mybatis-plus, 结果所有分页都失效了 原因 我这边的失效原因初步定为是因为mybatis-plus的自动配置和pageHelper的自动配置冲突了, 导致pageHelper的自动配置失效(最终是加上个配置类解决的) 解决方案 新建一个配置类 /**  * @A

  • pageHelper一对多分页解决方案示例

    目录 pageHelper 1.使用嵌套查询 2.使用自定义统计查询 pageHelper 是一个非常方便实用的 Java 分页插件,可以轻松实现数据库分页查询.而在一对多的情况下,如果要实现主表和从表的联合分页查询,可以采用以下两种解决方案: 1.使用嵌套查询 在 SQL 语句中使用嵌套查询,先在主表中查询出需要的数据信息,然后再根据这些信息去查询对应的从表数据.具体的 SQL 语法如下: SELECT m.*, (SELECT COUNT(1) FROM sub_tab s WHERE s.

  • SpringMVC解析JSON请求数据问题解析

    这几年都在搞前后端分离.RESTful风格,我们项目中也在这样用.前几天有人遇到了解析JSON格式的请求数据的问题,然后说了一下解析的方式,今天就写篇文章简单的分析一下后台对于JSON格式请求数据是怎么解析的. 先把例子的代码贴出来: 前端 <input type="button" value="测试JSON数据" onclick="testJSON()" /> <script type="text/javascrip

  • 使用Java进行Json数据的解析(对象数组的相互嵌套)

    这段时间我们在做一个英语翻译软件的小小小APP,涉及到了对Json数据的解析,所以特地来总结一下! 假设我们要对如下数据进行解析,其实在平时,返回的Json数据是很乱的,很难分清数据的关系,这是经过相关工具美化后的结果 { "translation": [ "爱" ], "basic": { "us-phonetic": "lʌv", "phonetic": "lʌv"

  • Android编程实现根据经纬度查询地址并对获取的json数据进行解析的方法

    本文实例讲述了Android编程实现根据经纬度查询地址并对获取的json数据进行解析的方法.分享给大家供大家参考,具体如下: 第一步:根据指定的URL从google 服务器上获得包含地址的json格式的数据(其还提供xml格式的,但json解析效率比xml高) private static StringBuffer getJSONData(String urlPath){ try { URL url = new URL(urlPath); HttpURLConnection httpURLCon

  • C#实现解析百度天气数据,Rss解析百度新闻以及根据IP获取所在城市的方法

    本文实例讲述了C#实现解析百度天气数据,Rss解析百度新闻以及根据IP获取所在城市的方法,分享给大家供大家参考.具体实现方法如下: 一.百度天气 接口地址:http://api.map.baidu.com/telematics/v3/weather?location=上海&output=json&ak=hXWAgbsCC9UTkBO5V5Qg1WZ9,其中ak是密钥,自行去申请即可,便于大家测试,楼主就公布并了自己的Key,这样可以直接获取到数据. 获取到的数据是这样的: 复制代码 代码如

  • Java编程通过匹配合并数据实例解析(数据预处理)

    本文研究的主要是Java编程通过匹配合并数据(数据预处理)的相关内容,具体如下. 数据描述 以下程序是对如下格式的数据进行合并处理. 这个表的每一行表示用户id及用户的特征.其中,一个用户只有一个特征向量,即第一列不会重复. 这张表的第一列,表示用户的id,第二列表示用户所看的电影,第三列表示用户对电影的打分(1-13分),第四列表示用户对电影的打分,但分值范围是1-5分. 问题描述 在做数据预处理时,如何将第二张表添加上用户特征呢?其实,方法很简单,将第二张表的用户id与第一张表的用户id进行

  • Servlet返回的数据js解析2种方法

    这篇文章主要介绍了Servlet返回的数据js解析2种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 方式1:Json 接收函数:ajax.responseText后面没括号 其实在之前所说的ajax中还遗留了一些问题就是,Servlet返回给js的数据是如何被js解析的呢? 之前只是发送了一句话,所以他就以html的格式进行解析就成功了,但是在实际中我们往往发送的数据是存在一个对象当中的又或者是一组对象当中的,我们应该如何发送呢? jso

  • 微信小程序跨页面传递data数据方法解析

    这篇文章主要介绍了微信小程序跨页面传递data数据方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Q:小程序怎么把页面data里的数据传到另外的页面? 或者小程序怎么吧表单里的数据传到另外的页面? A:1.可以使用url传递数据. 例如在A页面中传递数据,需要注意的是,wx.switchTab中的url不能传参数. wx.navigateTo({ url:'../pageB/pageB?name=raymond&gender=male'

  • sql获取存储过程返回数据过程解析

    这篇文章主要介绍了sql获取存储过程返回数据过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 就是在执行存储后,获取存储过程执行的数据并作为其他应的二次使用, 其实在代码中可以说是调用类似,具体操作如下: 创建一个存储过程: use [库名] go set ansi_null on GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE DBO.P_TEST ( @RBACK VARCHAR(20)

  • python3实现从kafka获取数据,并解析为json格式,写入到mysql中

    项目需求:将kafka解析来的日志获取到数据库的变更记录,按照订单的级别和订单明细级别写入数据库,一条订单的所有信息包括各种维度信息均保存在一条json中,写入mysql5.7中. 配置信息: [Global] kafka_server=xxxxxxxxxxx:9092 kafka_topic=mes consumer_group=test100 passwd = tracking port = 3306 host = xxxxxxxxxx user = track schema = track

  • SpringBoot Redis缓存数据实现解析

    这篇文章主要介绍了SpringBoot Redis缓存数据实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.启用对缓存的支持 spring对缓存的支持有两种方式: a.注解驱动的缓存 b.XML声明的缓存 本文主要介绍纯Java配置的缓存,那么必须在配置类上添加@EnableCaching,这样的话就能启动注解驱动的缓存. 2.使用Redis缓存 缓存的条目不过是一个键值对(Key-Value),其中key描述了产生value的操作和

随机推荐