解决n+1查询数据库问题
文章目录
- 1. 问题描述
- 2. 解决方法
- 3. 总结
1. 问题描述
在写项目中,可能会碰到一个问题:通过查询表A得到一个list结果,再对list中的n个元素各查询一次关联的表B。形成对数据库执行n+1次查询。这种代码会无形增加数据库的处理负担,影响整体性能。
举例:给定categoryId,查询dish和dish_flavor相关信息(dish表和dish_flavor表存在冗余字段dishId)。表的实体类结构如下:
-
dish:
@Data @AllArgsConstructor @NoArgsConstructor @TableName("dish") public class Dish {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer categoryId; } -
dish_flavor:
@Data @AllArgsConstructor @NoArgsConstructor @TableName("dish_flavor") public class DishFlavor {@TableId(type = IdType.AUTO)private Long id;private Long dishId;private String name;private String value; }
2. 解决方法
-
批量查询
先根据categoryId查询到所有的dish信息,然后提取所有dish的id,再根据dish_id批量查询得到dish_flavor信息,最后组合返回。- vo:
@Data @AllArgsConstructor @NoArgsConstructor @Builder public class DishFlavorVO {private Long id;private String name;private Integer categoryId;private List<DishFlavor> flavors = new ArrayList<>(); } - ServiceImpl:
@Service @Slf4j public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;/*** 方法 1:批量查询* @param categoryId* @return*/public List<DishFlavorVO> method1(Integer categoryId) {//1. 获取所有的dishesList<DishFlavorVO> dishFlavorVOS = dishMapper.getDishes(categoryId);//1.1 获取所有的dish_idList<Long> dishIds = dishFlavorVOS.stream().map(DishFlavorVO::getId).collect(Collectors.toList());//2.获得所有的dish_flavorList<DishFlavor> dishFlavors = dishMapper.selectFlavorsByDishIdList(dishIds);//3 聚合dish和dish_flavorMap<Long, List<DishFlavor>> flavorsMap = dishFlavors.stream().collect(Collectors.groupingBy(DishFlavor::getDishId));for (DishFlavorVO dishFlavorVO : dishFlavorVOS) {dishFlavorVO.setFlavors(flavorsMap.get(dishFlavorVO.getId()));}return dishFlavorVOS;}} - mapper:
<?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.example.solution.mapper.DishMapper"><select id="getDishes" resultType="com.example.solution.pojo.vo.DishFlavorVO">select * from dish where category_id = #{categoryId}</select><!--批量查询--><select id="selectFlavorsByDishIdList" resultType="com.example.solution.pojo.entity.DishFlavor">select * from dish_flavorwhere dish_id in<foreach collection="dishIds" separator="," open="(" close=")" item="dishId">#{dishId}</foreach></select></mapper>
- vo:
-
join联表查询
需要额外新建接收返回参数的类,再封装成返回给前端的vo。- item:
@Data @AllArgsConstructor @NoArgsConstructor public class DishesAndFlavorsItem {private Long id;private String name;private Integer categoryId;private Long fDishId;private Long fId;private String fName;private String fValue; } - ServiceImpl:
/*** 方法 2:联表查询* @param categoryId* @return*/ public List<DishFlavorVO> method2(Integer categoryId){List<DishFlavorVO> dishFlavorVOS = new ArrayList<>();//1. 联表查询List<DishesAndFlavorsItem> dishes = dishMapper.getDishesAndFlavors(categoryId);//2. 组合dish和dish_flavorMap<Long, List<DishesAndFlavorsItem>> collect = dishes.stream().collect(Collectors.groupingBy(DishesAndFlavorsItem::getFDishId));for (Map.Entry<Long, List<DishesAndFlavorsItem>> entry : collect.entrySet()) {List<DishFlavor> dishFlavors = new ArrayList<>();Long dishId = entry.getKey();List<DishesAndFlavorsItem> dishesAndFlavorsItems = entry.getValue();for (DishesAndFlavorsItem dishesAndFlavorsItem : dishesAndFlavorsItems) {DishFlavor dishFlavor = new DishFlavor();dishFlavor.setId(dishesAndFlavorsItem.getFId());dishFlavor.setValue(dishesAndFlavorsItem.getFValue());dishFlavor.setName(dishesAndFlavorsItem.getFName());dishFlavor.setDishId(dishesAndFlavorsItem.getFDishId());dishFlavors.add(dishFlavor);}DishFlavorVO dishFlavorVO = new DishFlavorVO();dishFlavorVO.setFlavors(dishFlavors);dishFlavorVO.setId(dishId);}return dishFlavorVOS; } - mapper:
<select id="getDishesAndFlavors" resultType="com.example.solution.pojo.item.DishesAndFlavorsItem">SELECTd.id as id,d.category_id as categoryId,df.dish_id as f_dishId,df.id as f_id,df.`name` as f_name,df.`value` as f_valueFROMdish as dLEFT JOINdish_flavor as df ON d.id = df.dish_idWHEREd.category_id = #{categoryId} </select>
- item:
3. 总结
可以通过批量查询或join联表查询来获取。使用批量查询需要分两次sql来查;使用join需要额外构建类来接收结果。如果效率需进一步提升,可使用redis缓存。
以上为个人学习分享,如有问题,欢迎指出:)
相关文章:
解决n+1查询数据库问题
文章目录 1. 问题描述2. 解决方法3. 总结 1. 问题描述 在写项目中,可能会碰到一个问题:通过查询表A得到一个list结果,再对list中的n个元素各查询一次关联的表B。形成对数据库执行n1次查询。这种代码会无形增加数据库的处理负担,影…...
DICOM 基础知识:深入理解DICOM数据结构与标签说明
目录 DICOM 图像概念 DICOM 图像关键特性: DICOM 文件结构 常见数据元素: 数据元素示例详解 DICOM-VR 数据类型说明 DICOM 标准支持的数据集 结语 DICOM 图像概念 DICOM(Digital Imaging and Communications in Medicine&…...
Git - 如何删除 push 过一次的文件链路追踪?
(以 target 文件夹为例)如果你已经在 .gitignore 中添加了 target/ 目录,但 target 文件夹仍然出现在 Git 的变更列表中,可能是因为它之前已经被添加到 Git 仓库中。即使你更新了 .gitignore,Git 仍然会跟踪这些文件。…...
软件测试学习总结
一.软件测试概念和目的 软件测试的概念: 测试模型(V模型) 软件测试就是在软件投入运行前,对软件需求分析、设计规格说明和编码实现的最终审查,它是软件质量保证的关键步骤。 通常对软件测试的定义有两种描述: 定义1:软件测试是为了发现错误而执行程序的过程 定义2:…...
c语言错题——#define对应的查找替换
文章目录 一、题目 提示:以下是本篇文章正文内容,下面案例可供参考 一、题目 分析 结构体向最长的char对齐,前两个位段元素一共42位,不足8位,合起来占1字节,最后一个单独1字节,一共3字节。另外…...
Visual Basic介绍及简单例子
Visual Basic(简称 VB)是一种由微软公司开发的包含协助开发环境的事件驱动编程语言。 一、主要特点 易于学习和使用: Visual Basic 具有直观的可视化开发环境,使用户可以通过拖放控件和设置属性的方式快速创建用户界面。对于初学者来说,这种方式非常容易上手,无需深入了…...
Matlab学习01-矩阵
目录 一,矩阵的创建 1,直接输入法创建矩阵 2,利用M文件创建矩阵 3,利用其它文本编辑器创建矩阵 二,矩阵的拼接 1,基本拼接 1) 水平方向的拼接 2)垂直方向的拼接 3…...
【复旦微FM33 MCU 外设开发指南】外设篇1——硬件除法器
前言 本系列基于复旦微FM33LC0系列单片机的DataSheet编写,旨在提供一些开发指南。 本文章及本系列其他文章将持续更新,本系列其它文章请跳转【复旦微FM33 MCU 外设开发指南】总集篇 本文章最后更新日期:2024/10/24 文章目录 前言用途工作流…...
在元神操作系统启动时自动执行任务脚本
1. 背景 本文主要介绍让元神操作系统启动时自动执行任务脚本的方法,适用于无人化任务执行目的。将任务脚本及相关的应用程序准备好之后,把装有元神操作系统的U盘插入目标电脑,然后打开电脑电源就会自动完成所设置的任务。 2. 方法 &#x…...
JAVA学习-练习试用Java实现“判断是否为等边三角形的方法”
问题: 定义一个三角形类(Triangle),包含三个边长(a, b, c)属性,并实现一个判断是否为等边三角形的方法。 解答思路: 下面是一个简单的 Triangle 类定义,其中包含了三个…...
Leetcode 140 Word Break II
题意:给定一个string以及一个wordDict,要求返回一个vector<string> ,这个vector中的string都是word Dict中的组合 Input: s “catsanddog”, wordDict [“cat”,“cats”,“and”,“sand”,“dog”] Output: [“cats and dog”,“cat sand dog”…...
文理学院数据库应用技术实验报告0
文理学院数据库应用技术实验报告0 实验内容 打开cmd,利用MySQL命令连接MySQL服务器。 mysql -u root -p查看当前MySQL服务实例使用的字符集(character)。 SHOW VARIABLES LIKE character_set_server;查看当前MySQL服务实例支持的字符序(collation)。 SHOW VARIABLES LIKE c…...
Bootstrap 4 按钮
Bootstrap 4 按钮 Bootstrap 4 是一个流行的前端框架,它提供了大量的组件和样式,用于快速开发响应式和移动设备优先的网页。在本文中,我们将重点讨论 Bootstrap 4 中的按钮组件,包括它们的基本用法、样式选项和自定义方法。 基本按钮 在 Bootstrap 4 中,创建一个基本按…...
【笔记】LLM位置编码之标准位置编码
标准位置编码 起源原理证明:对于任何固定的偏移量 k k k, P E p o s k PE_{posk} PEposk可以表示为 P E p o s PE_{pos} PEpos的线性函数。计算 P E p o s k 与 P E p o s PE_{posk} 与PE_{pos} PEposk与PEpos的内积结论 通俗理解缺点 起源 由…...
环 境 配 置
01 Ubuntu18.04中QT环境 1. 下载安装包 官网 http://download.qt.io/archive/qt/5.9/5.9.1/qt-opensource-linux-x64-5.9.1.run 国内镜像服务器 https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.9/5.9.1/qt-opensource-linux-x64-5.9.1.run QQ群 ...... 2. 安装 把下载…...
理解dbt artifacts及其实际应用
dbt是数据分析领域的一种变革性工具,它使数据专业人员能够对仓库中的数据进行转换和建模。它的强大功能之一是生成dbt artifacts:dbt运行的结构化输出,提供对dbt项目及其操作的深入了解。 dbt 构件介绍 dbt构件是每次dbt运行时生成的JSON文…...
100种算法【Python版】第15篇——KMP算法
本文目录 1 算法原理1.1 部分匹配表2 实现步骤3 示例说明4 python实例5 算法应用领域1 算法原理 KMP(Knuth-Morris-Pratt)算法是一种用于高效字符串匹配的算法。它通过预处理模式字符串,构建一个部分匹配表(前缀函数),以避免重复比较,从而提高匹配效率。KMP 算法通过利…...
【软件工程】软件项目管理/工程项目管理复习资料
第一章 软件项目管理概述习题 一. 填空题 实现项目目标的制约因素有( 项目范围 )、( 成本 )、( 进度计划 )、( 客户满意度 )等。 项目管理( 启动过程组 )、…...
C语言基础题(大合集2)
1. 时间转换 给定秒数 --> 输出秒数 转化成 时/分/秒 //时间转换 //给定秒数 --> 转换成 小时/分/秒 int main() {//输入int seconds 0;int h 0;//小时int m 0;//分钟int s 0;//秒scanf("%d", &seconds);//计算h seconds / 60 / 60;m seconds / 60…...
Stable Diffusion视频插件Ebsynth Utility使用方法
在Stable Diffusion中安装完Ebsynth Utility后,就可以开始试用了。 启动Stable Diffusion后,出面画面: 1、步骤1:视频分帧及生成蒙板帧 填入工程目录,选择上传所用的视频文件:注意对目录命名的要求-不能有…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
