项目实战--Spring Boot与PageHelper的集成及线程污染解决

一、PageHelper使用背景

公司要做个简单管理系统,要我搭建Spring Boot+MyBatis+PageHelper+Redis的项目框架然后交i给实习生来开发。这个其实很简单,但是遇到搭建和使用过程中PageHelper有好多小坑,就记录一下,避免再踩。
版本选择:

JDK 8
SpringBoot 2.5.0
MyBatis 3.5.7
PageHelper 5.2.0
二、步骤
2.1 新建Spring Boot项目

如果过程中,选择java版本时发现没有java8版本,只有java17和java21
在这里插入图片描述
原因:

spring2.X版本在20231124日停止维护,因此创建spring项目时不再有2.X版本的选项,只能从3.1.X版本开始选择
而Spring3.X版本不支持JDK8,JDK11,最低支持JDK17,因此JDK11也无法选择

解决:
目前阿里云支持创建Spring2.X版本的项目

修改Server URL为:https://start.aliyun.com

在这里插入图片描述
这样就可以创建啦

2.2 引入依赖

在pom.xml文件中添加相关依赖:

<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- MyBatis Starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!-- PageHelper --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.0</version></dependency>
</dependencies>
2.3 配置PageHelper

在application.yml文件中进行PageHelper的基本配置:

pagehelper:helper-dialect: mysql # 指定数据库方言为MySQLreasonable: true # 分页合理化,启用后如果页码<1则查询第一页,页码>总页数则查询最后一页。support-methods-arguments: true # 支持通过Mapper接口参数来传递分页参数params: count=countSql # 指定count查询的参数名称
2.4 配置MyBatis

让PageHelper与MyBatis集成,还需在SpringBoot配置文件中添加MyBatis的相关配置:

mybatis:mapper-locations: classpath:/mappers/*.xml # Mapper XML文件的位置type-aliases-package: com.example.demo.entity # 实体类的包路径
2.5 编写Mapper接口和XML

User实体类:

public class User {private Long id;private String name;private String email;// getters and setters
}

对应的Mapper接口:

public interface UserMapper {@Select("SELECT * FROM users")List<User> selectAll();
}

Mapper XML文件则包含分页查询的SQL:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper"><select id="selectAll" resultType="com.example.demo.entity.User">SELECT * FROM users</select>
</mapper>
2.6 使用PageHelper进行分页

Service层使用PageHelper进行分页查询:


@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public PageInfo<User> getUsers(int pageNum, int pageSize) {PageHelper.startPage(pageNum, pageSize);List<User> users = userMapper.selectAll();return new PageInfo<>(users);}
}

在Controller层,通过RESTful接口来调用分页查询:


@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMappingpublic PageInfo<User> getUsers(@RequestParam(defaultValue = "1") int pageNum,@RequestParam(defaultValue = "10") int pageSize) {return userService.getUsers(pageNum, pageSize);}
}

这就实现简单的分页查询功能,通过PageHelper来控制分页参数。

三、问题解决

(1)分页无效或查询结果为空

确保在调用分页查询方法前,已经正确调用了PageHelper.startPage方法。
检查数据库连接是否正常,SQL查询语句是否正确。

(2)分页参数不生效

检查Controller层是否正确接收并传递分页参数。
确保application.yml中配置的support-methods-arguments为true

(3)性能问题

对于大数据量的表,分页查询可能会带来性能问题。可以通过增加索引、优化SQL查询等方式提高性能。

(4)使用过程中线程污染,无缘故的分页
前端调用一个未分页的接口,出现数据丢失或者报错的情况:
现象:前端调用一个只查询一条数据的接口,该接口执行的SQL是:

select id,statistics_month,update_time from business_statistics_record
order by statistics_month desclimit 1

在这里插入图片描述
但是实际上,日记打印出来的SQL:limit 1 limit ?, ?;就出现查询异常:
在这里插入图片描述
经过排查,真正原因是因为调用自定义分页出现问题:PageHelper.startPage(pageNum, pageSize);调用之后并没有消费,分页参数一直保存在线程中,当这个线程再次调用的时候,导致莫名奇妙的加上limit关键字。
查看PageHelper源码看到:

PageHelper 方法使用静态的 ThreadLocal参数,分页参数和线程是绑定的。只要保证在 PageHelper方法调用后紧跟MyBatis查询方法,这就是安全的。因为 PageHelper在finally代码段中自动清除ThreadLocal存储的对象。

而随机加上limit关键字,查看ThreadLocal LOCAL_PAGE值的变化,只有当线程复用的时候才会出现LOCAL_PAGE已被实例化。
在这里插入图片描述
为避免使用PageHelper过程中如果出现无缘无故出现分页,
在使用了PageHelper.startPage()后需要紧接着 MyBatis 查询方法。
最好是在执行sql的方法加上finally语句清理page缓存:
在这里插入图片描述

这个afterAll()方法中:
在这里插入图片描述
而 clearPage()方法的功能是:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/866978.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

std::__cxx11::basic_string 和std::basic_string的不同

问题描述&#xff1a; 源文件中定义的函数是 &#xff1a; void setAccessKeyId&#xff08;std::string&#xff09; 但是使用centos中 g4.8.5 编译能正常编译过&#xff0c;debian系统中使用 centos 10.2版本编译不过 提示找不到定义&#xff1a;setAccessKeyId(std::__cx…

c++:#include 某文件.h底层如何寻找其.cpp实现

在C中&#xff0c;当你编写了一个头文件&#xff08;如MyLibrary.h&#xff09;和对应的实现文件&#xff08;如MyLibrary.cpp&#xff09;时&#xff0c;其他源文件&#xff08;如main.cpp&#xff09;只需要包含头文件&#xff08;#include "MyLibrary.h"&#xff…

C语言_操作符

目录 算术操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用&#xff0c;函数调用&#xff0c;结构成员 表达式求值 隐式类型转换 算术转换 操作符的属性 练习题 代码仓库 算术操作符 加()&#x…

部署过docker后,防火墙firewall与iptables的基本指令

一、iptables【无需stop docker服务】 如果服务器中部署了docker&#xff0c;优先选用iptables 1. 记录关闭docker中运行的mongoDB的27017端口&#xff1a; 由于docker与iptables存在配置规则&#xff0c;因此要修改docker相关端口的可访问性时需要使用下面的语句&#xff1a…

自定义通信协议实例

自定义通信协议是指通信双方为了实现特定功能或满足特定需求&#xff0c;在通信过程中自行约定的一种通信规则。这种协议通常包括数据的格式、传输方式、校验方法等内容&#xff0c;以确保通信双方能够正确地理解和交换信息。以下是关于自定义通信协议的一些详细解释和示例&…

git上传时出现了main master的问题解决

git 上传时 出现了main master 这个问题通常出现在Git版本控制系统中&#xff0c;当你尝试上传代码到远程仓库时&#xff0c;可能会看到一个提示&#xff0c;关于"main"和"master"的。 解释&#xff1a; Git 2020年发布了新的默认分支名称"main&qu…

智能插座搭配BIOS唤醒功能实现远程定时开关机

智能插座 智能插座凭借其强大的联网能力&#xff0c;不仅能够实现远程操控开关电源&#xff0c;部分高端型号更是集成了电量统计与自动化操作功能&#xff0c;为用户带来了前所未有的便捷体验。以下是我对几款体验过的智能插座的简要评价&#xff0c;因版本差异可能有所不同。…

工业交换机端口统计功能

工业交换机端口统计功能不仅是一项技术手段&#xff0c;更是一双透视企业网络健康状态的慧眼。通过这一功能&#xff0c;企业能够实时捕捉到网络中每一个端口的流量情况&#xff0c;这不仅仅是数据的积累&#xff0c;更是对网络脉搏的精准把握。当网络的每一个脉动都被记录在案…

RecyclerView实现手势滑动选中相册图片

要使用RecyclerView实现手势滑动选中相册图片的功能&#xff0c;你需要以下几个步骤&#xff1a; 创建含有图片资源的ViewHolder&#xff0c;继承自RecyclerView.ViewHolder&#xff0c;用于显示相册中的每个图片。 创建一个Adapter&#xff0c;继承自RecyclerView.Adapter&…

建智慧医院核心:智能导航系统的功能全析与实现效益

在数字化转型的浪潮中&#xff0c;智慧医院的建设是医疗行业数字化转型的关键步骤。随着医院规模的不断扩大和医疗设施的日益复杂&#xff0c;传统的静态不连续的导航方式已无法满足患者的需求。院内智能导航系统&#xff0c;作为医疗数字化转型的关键组成部分&#xff0c;正逐…

怎么做IDS,入侵检测

要在Linux系统上实现入侵检测系统&#xff08;IDS&#xff09;&#xff0c;您可以选择许多开源或商业工具。以下是使用开源工具Snort和Suricata来实施入侵检测系统的详细步骤&#xff1a; 选择IDS工具 1. Snort Snort是一款流行的开源网络入侵检测和防御系统&#xff08;IDS…

禅心驭智,展望软件未来新纪元

禅心驭智&#xff0c;展望软件未来新纪元 阿弥陀佛&#xff0c;善哉善哉。于这瞬息万变的数字时代&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;如同璀璨星辰&#xff0c;引领着软件开发领域步入一个前所未有的新纪元。贫僧观此变革&#xff0c;心中满是感慨与期待…

freemarker取值使用

格式化 格式化为字符串 ${entity.name!} 格式化为数字 ${entity.id?c} 格式化为时间 ${detail.date?string("yyyy-MM-dd HH:mm:ss")} 格式化为金额 判断非空 <#if detail.aEntity?? && detail.aEntity.has?? && detail.aEntity.has1>-- …

进程监视器,进程资源管理器

进程资源管理器 - Sysinternals | Microsoft Learn 进程监视器 - Sysinternals | Microsoft Learn PC查看资源占用

环境检测聚四氟乙烯微波消解罐 特氟龙反应釜 适用于COD测定

COD消解罐是实验室中用于测定水样中化学需氧量&#xff08;Chemical Oxygen Demand&#xff0c;简称COD&#xff09;的一种专用设备。化学需氧量是衡量水体污染程度的一个重要参数&#xff0c;它表示在一定条件下&#xff0c;水样中的有机物质和部分无机物质被氧化的程度。以下…

中霖教育:二建报名成功后怎么审核?

【中霖教育怎么样】【中霖教育靠谱吗】 在成功完成二级建造师资格考试的报名流程后&#xff0c;需要准备后续的审核阶段&#xff0c;审核是否通过关乎考生是否能顺利参加考试&#xff0c;审核的方式包括&#xff1a;现场审核、网络审核以及考试后的审核。 某些地区会要求考生…

AI文字图片人脸生成原创视频文生图生肖生小程序开发

AI文字图片人脸生成原创视频文生图生肖生小程序开发 无限开 0.12生成 图生视频 AI技术在生成文字、图片、人脸以及视频方面已经取得了显著的进步。以下是一些可能包含在AI文字图片人脸生成原创视频小程序中的功能列表&#xff1a; 文字转视频&#xff1a; 输入文字或文章&…

x264_ratecontrol_mb解析

目的 x264_ratecontrol_mb调用发生在宏块编码之后,如果开启了AQ,则在AQ之后,由slice_write调用,从函数名称看,是用于宏块级码率控制,但是它与调用宏块QP没有直接的关系,该函数的主要目的由两个: 更新rc->qpa_aq和rc->qpa_rc的值rc->qpa_aq为当前slice目前宏块…

2024.7.5

2024.7.5 【向之所欣&#xff0c;俯仰之间&#xff0c;已为陈迹。】 Thursday 五月三十 组合 数学&#xff01; 可能公式比较多 二项式&#xff01; $$ \begin{pmatrix}n\m\end{pmatrix}\begin{pmatrix}n-1\m-1 \end{pmatrix}\begin{pmatrix} n-1 \m\end{pmatrix} \begi…

使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击(一)

文章目录 概要开发思路界面编辑新建工程&#xff0c;设置界面大小导入素材场景编辑场景编辑 移动组件输入组件添加移动状态脚本定位组件 概要 飞船设计游戏的学习&#xff0c;如下所示 原视频地址&#xff1a; https://www.youtube.com/playlist?listPL9FzW-m48fn09w6j8Now…