当前位置: 首页 > news >正文

Spring Boot项目如何使用MyBatis实现分页查询

 写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭!
用知识改变命运,用知识成就未来!加油 (ง •̀o•́)ง (ง •̀o•́)ง

文章目录

  • 为什么需要分页查询
    • 减少数据库压力
    • 减少网络传输数据量
    • 提高系统的稳定性
    • 提升用户体验
  • 原始的实现方式
    • 计算偏移量
    • 在Mapper接口中定义查询方法
    • 编写SQL语句
    • 开发流程及完整代码
      • Controller层
      • Service实现类
      • Mapper接口方法
      • xml文件SQL
  • 使用插件实现
    • 引入分页插件依赖
    • Service实现类
    • xml文件SQL
    • 与原始分页的不同

为什么需要分页查询

 分页查询是一种常见的数据库查询技术,用于将查询结果分成多个页面展示,而不是一次性返回所有数据。使用分页查询主要是为了减少数据库压力、减少网络传输数据量、提高系统的稳定性、提高客户体验

减少数据库压力

 一次性查询全部数据(例如百万条记录)会占用大量的资源(CPU、内存、I/O),导致响应变慢甚至系统崩溃。分页后,每次仅查询少量数据(如每页100条),可以显著降低负载。
查询执行路径

减少网络传输数据量

 分页查询每次只传输当前页的数据,相比于全表查询会极大的减少网络传输的数据量,降低网络带宽的占用。

提高系统的稳定性

 后端服务处理分页查询时,单次处理的数据量可控,避免因一次性加载大数据导致内存耗尽出现 OOM 问题。对于前端也由于无需一次性渲染大量的数据而减少了内存崩溃的风险。

提升用户体验

 分页查询由于单次查询的数据量少,后端与前端可以快速的处理相关的数据。用户无需进行长时间的等待,极大的提高了客户的体验。

原始的实现方式

 如果不使用分页查询相关的插件需要我们自己计算分页查询的偏移量offset,还需要手动查询结果集以及数据总条数,并且在相关的 Mapper.xml 中定义分页查询的 SQL 语句。主要实现步骤如下:

计算偏移量

 手动分页查询需要我们通过在 SQL 语句中添加分页相关的语法来实现,例如在 MySQL 中的语法:

SELECT * FROM users LIMIT #{pageSize} offset #{offset};

其中,#{offset} 表示偏移量,但是前端的分页查询请求中一般只有查询第几页 page 和每页的大小 pageSize。需要我们先计算一下偏移量是多少。

 需要注意前端传的 page 是从 0 开始的还是从 1 开始的。

  • 0 开始则 offset = page * pageSize
  • 1 开始则 offset = (page - 1) * pageSize

在Mapper接口中定义查询方法

/*** 分页查询结果集* @param page* @param offset* @param name* @param categoryId* @param status* @return*/
List<DishVO> pageQuery(int page, int offset, String name, Integer categoryId, Integer status);/*** 查询总条数* @return*/
int getTotalSize();

编写SQL语句

<mapper namespace="com.sky.mapper.DishMapper"><insert id="insert" useGeneratedKeys="true" keyProperty="id">insert into dish (name, category_id, price, image, description, status, create_time, update_time, create_user, update_user)values (#{name}, #{categoryId}, #{price}, #{image}, #{description},#{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})</insert><select id="pageQuery" resultType="com.sky.vo.DishVO">select d.*, c.name as categoryName from dish d left outer join category c on d.category_id = c.id<where><if test="name != null">and d.name like concat('%', #{name}, '%')</if><if test="categoryId != null">and d.category_id = #{categoryId}</if><if test="status != null">and d.status = #{status}</if></where>order by d.create_time desclimit #{page}offset #{offset}</select><select id="getTotalSize" resultType="java.lang.Integer">select count(*) from dish;</select>
</mapper>

开发流程及完整代码

 在开发过程中 由外而内 进行开发效率会更高一些,我们一般不需要先写 Mapper.xml 中的 SQL语句,再定义Mapper接口中的方法,然后再通过 Service类 中进行调用。

 一般会从 Service类 开始写起,然后再通过编辑器的快捷方式帮助我们生成相关的代码,再一层一层的实现。

Controller层

@GetMapping("/page")
@ApiOperation("菜品分页查询")
public Result<PageResult> pageQuery(DishPageQueryDTO dishPageQueryDTO) {log.info("菜品分页查询开始[{}]", dishPageQueryDTO);return dishService.pageQuery(dishPageQueryDTO);
}

Service实现类

@Override
public Result<PageResult> pageQuery(DishPageQueryDTO dishPageQueryDTO) {// 计算偏移量int offset = (dishPageQueryDTO.getPage() - 1) * dishPageQueryDTO.getPageSize();// 查询当前页的数据List<DishVO> dishVOList = dishMapper.pageQuery(dishPageQueryDTO.getPageSize(), offset, dishPageQueryDTO.getName(),dishPageQueryDTO.getCategoryId(), dishPageQueryDTO.getStatus());// 查询数据库中的总条数int total = dishMapper.getTotalSize();PageResult pageResult = new PageResult();pageResult.setTotal(total);pageResult.setRecords(dishVOList);log.info("分页查询结果为[{}]", pageResult);return Result.success(pageResult);
}

Mapper接口方法

/*** 分页查询结果集* @param page* @param offset* @param name* @param categoryId* @param status* @return*/
List<DishVO> pageQuery(int page, int offset, String name, Integer categoryId, Integer status);/*** 查询总条数* @return*/
int getTotalSize();

xml文件SQL

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper"><insert id="insert" useGeneratedKeys="true" keyProperty="id">insert into dish (name, category_id, price, image, description, status, create_time, update_time, create_user, update_user)values (#{name}, #{categoryId}, #{price}, #{image}, #{description},#{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})</insert><select id="pageQuery" resultType="com.sky.vo.DishVO">select d.*, c.name as categoryName from dish d left outer join category c on d.category_id = c.id<where><if test="name != null">and d.name like concat('%', #{name}, '%')</if><if test="categoryId != null">and d.category_id = #{categoryId}</if><if test="status != null">and d.status = #{status}</if></where>order by d.create_time desclimit #{page}offset #{offset}</select><select id="getTotalSize" resultType="java.lang.Integer">select count(*) from dish;</select>
</mapper>

使用插件实现

 使用分页插件可以极大的简化分页查询实现。虽然实现的主要原理还是通过原始实现方式中提到的逻辑,但是通过分页插件我们就可以少写很多代码而且一般分页插件(例如 PageHelper) 会通过动态 SQL 的构建和优化,能够有效避免传统分页方法的性能问题。

 使用插件进行分页查询只需要修改一下上述原始实现方式的Service类xml 文件中的 SQL 语句即可。

引入分页插件依赖

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>

Service实现类

@Override
public Result<PageResult> pageQuery(DishPageQueryDTO dishPageQueryDTO) {PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());Page<DishVO> page = dishMapper.pageHelperQuery(dishPageQueryDTO);PageResult pageResult = new PageResult();pageResult.setTotal(page.getTotal());pageResult.setRecords(page.getResult());log.info("分页查询结果为[{}]", pageResult);return Result.success(pageResult);}

xml文件SQL

<select id="pageHelperQuery" resultType="com.sky.vo.DishVO">select d.*, c.name as categoryName from dish d left outer join category c on d.category_id = c.id<where><if test="name != null">and d.name like concat('%', #{name}, '%')</if><if test="categoryId != null">and d.category_id = #{categoryId}</if><if test="status != null">and d.status = #{status}</if></where>order by d.create_time desc
</select>

与原始分页的不同

 使用分页插件进行分页不需要手动计算分页查询的偏移量,在写SQL语句时也不需要显式地使用 LIMITOFFSET 来实现分页。而且分页插件也会直接将查询的结果集总条数封装到 Page对象 中,不需要我们手动的查询结果集和总条数。


  1. mysql开启缓存、设置缓存大小、缓存过期机制
  2. PageHelper分页插件最新源码解读及使用
  3. 苍穹外卖

相关文章:

Spring Boot项目如何使用MyBatis实现分页查询

写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油&#xff0c;冲鸭&#x…...

飞行汽车中的无刷外转子电机、人形机器人中的无框力矩电机技术解析与应用

重点:无刷外转子电机与无框力矩电机&#xff1a;技术解析与应用对比 在现代工业自动化和精密机械领域&#xff0c;无刷电机因其高效、低噪音和高可靠性而备受青睐。其中&#xff0c;无刷外转子电机和无框力矩电机更是以其独特的结构和性能特点&#xff0c;成为众多应用场景中的…...

FreeRTOS学习 --- 队列集

队列集简介 一个队列只允许任务间传递的消息为同一种数据类型&#xff0c;如果需要在任务间传递不同数据类型的消息时&#xff0c;那么就可以使用队列集 &#xff01; 作用&#xff1a;用于对多个队列或信号量进行“监听”&#xff0c;其中不管哪一个消息到来&#xff0c;都可让…...

【R语言】R语言安装包的相关操作

一、管理R语言安装包 1、安装R包 install.packages() 2、查看已安装的R包 installed.packages() 3、更新R包 update.packages() 4、卸载R包 remove.packages() 二、加载R语言安装包 打开R语言时&#xff0c;基础包&#xff08;base包&#xff09;会自动被加载到内存中…...

15.[前端开发]Day15-HTML+CSS阶段练习(网易云音乐四)

完整代码 01_网易云-header <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"wid…...

【基于SprintBoot+Mybatis+Mysql】电脑商城项目之用户登录

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【Spring篇】【计算机网络】【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;1.登录-持久层 &…...

测试方案和测试计划相同点和不同点

在软件测试领域&#xff0c;测试方案与测试计划皆为举足轻重的关键文档&#xff0c;尽管它们有着紧密的关联&#xff0c;但在目的与内容层面存在着显著的差异。相同点&#xff1a; 1.共同目标&#xff1a;测试方案和测试计划的核心目标高度一致&#xff0c;均致力于保障软件的…...

c++提取矩形区域图像的梯度并拟合直线

c提取旋转矩形区域的边缘最强梯度点&#xff0c;并拟合直线 #include <opencv2/opencv.hpp> #include <iostream> #include <vector>using namespace cv; using namespace std;int main() {// 加载图像Mat img imread("image.jpg", IMREAD_GRAYS…...

Unity Shader Graph 2D - 角色身体电流覆盖效果

在游戏中,通常会有游戏角色受到“电击”的效果,此时游戏角色身体上会覆盖有电流,该效果能表明游戏角色的当前状态,让玩家能够获得更直观更好的体验。 那么如何实现呢 首先创建一个ShaderGraph文件,命名为Current,再创建对应的材质球M_Current。 基础的资源显示 老规矩,…...

【LLM-agent】(task4)搜索引擎Agent

note 新增工具&#xff1a;搜索引擎Agent 文章目录 note一、搜索引擎AgentReference 一、搜索引擎Agent import os from dotenv import load_dotenv# 加载环境变量 load_dotenv() # 初始化变量 base_url None chat_model None api_key None# 使用with语句打开文件&#xf…...

携程Java开发面试题及参考答案 (200道-下)

insert 一行数据的时候加的是什么锁?为什么? 在 MySQL 中,当执行 INSERT 操作插入一行数据时,加锁的情况会因存储引擎和具体的事务隔离级别而有所不同。一般来说,在 InnoDB 存储引擎下,INSERT 操作加的是行级排他锁(Row Exclusive Lock),以下详细说明原因。 行级排他…...

GWO优化SVM回归预测matlab

灰狼优化算法&#xff08;Grey Wolf Optimizer&#xff0c;简称 GWO&#xff09;&#xff0c;是由澳大利亚格里菲斯大学的 Mirjalii 等人于 2014 年提出的群智能优化算法。该算法的设计灵感源自灰狼群体的捕食行为&#xff0c;核心思想是对灰狼社会的结构与行为模式进行模仿。 …...

QMK启用摇杆和鼠标按键功能

虽然选择了触摸屏&#xff0c;我仍选择为机械键盘嵌入摇杆模块&#xff0c;这本质上是对"操作连续性"的执着。   值得深思的是&#xff0c;本次开发过程中借助DeepSeek的代码生成与逻辑推理&#xff0c;其展现的能力已然颠覆传统编程范式&#xff0c;需求描述可自动…...

Unity实现按键设置功能代码

一、前言 最近在学习unity2D&#xff0c;想做一个横版过关游戏&#xff0c;需要按键设置功能&#xff0c;让用户可以自定义方向键与攻击键等。 自己写了一个&#xff0c;总结如下。 二、界面效果图 这个是一个csv文件&#xff0c;准备第一列是中文按键说明&#xff0c;第二列…...

基于物联网技术的实时数据流可视化研究(论文+源码)

1系统方案设计 根据系统功能的设计要求&#xff0c;展开基于物联网技术的实时数据流可视化研究设计。如图2.1所示为系统总体设计框图&#xff0c;系统以STM32单片机做为主控制器&#xff0c;通过DHT11、MQ-2、光照传感器实现环境中温湿度、烟雾、光照强度数据的实时检测&#x…...

list容器(详解)

1. list的介绍及使用 1.1 list的介绍&#xff08;双向循环链表&#xff09; https://cplusplus.com/reference/list/list/?kwlist&#xff08;list文档介绍&#xff09; 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭…...

Elasticsearch基本使用详解

文章目录 Elasticsearch基本使用详解一、引言二、环境搭建1、安装 Elasticsearch2、安装 Kibana&#xff08;可选&#xff09; 三、索引操作1、创建索引2、查看索引3、删除索引 四、数据操作1、插入数据2、查询数据&#xff08;1&#xff09;简单查询&#xff08;2&#xff09;…...

17.3.4 颜色矩阵

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵&#xff08;Matrix&#xff09;是一个按照长方阵列排列的复数或实数集合&#xff0c;类似于数组。 由…...

FPGA 时钟多路复用

时钟多路复用 您可以使用并行和级联 BUFGCTRL 的组合构建时钟多路复用器。布局器基于时钟缓存 site 位置可用性查找最佳布局。 如果可能&#xff0c;布局器将 BUFGCTRL 布局在相邻 site 位置中以利用专用级联路径。如无法实现&#xff0c;则布局器将尝试将 BUFGCTRL 从…...

机器学习10

自定义数据集 使用scikit-learn中svm的包实现svm分类 代码 import numpy as np import matplotlib.pyplot as pltclass1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4, 1.1]])class2_points np.array([[3.2, 3.2],[3.7, 2.9],…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...