优化多表联表查询的常见方法归纳

目录

一、使用mybatis的嵌套查询

二、添加表冗余字段,减少联表查询需求

三、分表预处理,前端再匹配


一、使用mybatis的嵌套查询

【场景说明】

前端需要展示一张列表,其中的字段来源于多张表,如何进行查询优化?

【需求分析】

传统的联表查询使用左外连接连接四张表,整体查询从笛卡儿积开始优化,效率着实是低,我们可以使用mybatis 嵌套查询。所谓嵌套查询,就是将 原来多表的联合查询语句拆成多个单表的查询,再使用mybatis的语法嵌套在一起。

实现方式

首先你得了解Mybatis嵌套查询的一些语法情况:

1. association: 处理一对一、一对多嵌套、返回一个查询实体

2. collection:处理多对多嵌套、返回多个查询实体

3. resultMap:用于映射查询数据的实体类

【实现步骤】

分析该场景需求只需要通过id字段去其他表查找对应数据,属于一对多模型,使用association

(其中由于设备表只需要一个统计数量的字段,直接联表就好了)

1. 编写实现基本功能的语句:

SELECTn.id,n.node_name,n.address,n.business_type,n.region_id,n.partner_id,n.create_time,n.update_time,n.create_by,n.update_by,n.remark,COUNT(v.id) AS vm_count
FROMtb_node nLEFT JOINtb_vending_machine v ON n.id = v.node_id
GROUP BYn.id;

2. 实现基本的Mybatis语句:

注意不用resultType 而是使用 resultMap

    <select id="selectNodeVoList" parameterType="Node" resultMap="NodeVoResult">SELECTn.id,n.node_name,n.address,n.business_type,n.region_id,n.partner_id,n.create_time,n.update_time,n.create_by,n.update_by,n.remark,COUNT(v.id) AS vm_countFROMtb_node nLEFT JOINtb_vending_machine v ON n.id = v.node_id<where><if test="nodeName != null  and nodeName != ''"> and n.node_name like concat('%', #{nodeName}, '%')</if><if test="regionId != null "> and n.region_id = #{regionId}</if><if test="partnerId != null "> and n.partner_id = #{partnerId}</if></where>GROUP BYn.id</select>

3. 编写resultMap

<resultMap id="NodeVoResult" type="NodeVo"><result property="id"    column="id"    /><result property="nodeName"    column="node_name"    /><result property="address"    column="address"    /><result property="businessType"    column="business_type"    /><result property="regionId"    column="region_id"    /><result property="partnerId"    column="partner_id"    /><result property="createTime"    column="create_time"    /><result property="updateTime"    column="update_time"    /><result property="createBy"    column="create_by"    /><result property="updateBy"    column="update_by"    /><result property="remark"    column="remark"    /><result property="vmCount" column="vm_count"    /><association property="region" javaType="Region" column="region_id" select="com.dkd.manage.mapper.RegionMapper.selectRegionById"/><association property="partner" javaType="Partner" column="partner_id" select="com.dkd.manage.mapper.PartnerMapper.selectPartnerById"/></resultMap>

 4. VO对象说明

NodeVo对象包含了 Node实体、Region实体、Partner实体三个实体、vmCount设备数量字段

@Data
@AllArgsConstructor
@NoArgsConstructor
public class NodeVo extends Node{// 区域private Region region;// 合作商private Partner partner;// 设备数量private Integer vmCount;
}

二、添加表冗余字段,减少联表查询需求

【场景说明】

前端还是需要展示这一张表,包含了员工表、角色表、区域表等多表字段

【实现方式】

主体是员工数据,对于其他两张表数据使用并不多。基于此我们这次可以做这样一种处理:在设计数据表结构的时候,将region表的归属区域字段、role表的角色字段以冗余字段的形式一并设计入emp表。这样原先需要联表的需求就退化成单表查询了!

【实体说明】

/*** 人员列表对象 tb_emp* * @author weizhicong* @date 2024-10-21*/
public class Emp extends BaseEntity
{private static final long serialVersionUID = 1L;/** 主键 */private Long id;/** 人员名称 */@Excel(name = "人员名称")private String userName;/** 所属区域Id */private Long regionId;/** 归属区域 */@Excel(name = "归属区域")private String regionName;/** 角色id */private Long roleId;/** 角色编号 */private String roleCode;/** 角色名称 */@Excel(name = "角色名称")private String roleName;/** 联系电话 */@Excel(name = "联系电话")private String mobile;...........    }

【方法缺陷说明】数据一致性问题!

这种实现方式虽然优化了查询效率问题。但提高了数据库表设计的耦合度。具体表现在:当需要修改区域表名称字段、或者修改角色表的角色字段信息时,可能会导致数据的不同步,违反了数据一致性的问题。

【改进步骤】

为了解决这个问题,我们需要进行同步更新操作,具体地,在每次更新区域表或角色表字段的同时,调用更新员工表的方法,进行同步更新,同时注意事务的处理

1. 在EmpMapper中定义好更新员工表的方法:

/*** 根据区域ID更新区域信息*/@Update("update tb_emp set region_name = #{regionName} where region_id = #{regionId}")public int updateByRegionId(@Param("regionName") String regionName, @Param("regionId") Long regionId);

2. 在修改区域表的时候,注入EmpMapper,并调用该方法

注意添加事务注解!!

    /*** 修改区域管理* * @param region 区域管理* @return 结果*/@Override@Transactional(rollbackFor = Exception.class)public int updateRegion(Region region){// 1. 更新区域信息region.setUpdateTime(DateUtils.getNowDate());int result =  regionMapper.updateRegion(region);//2. 同步更新员工表的区域名称empMapper.updateByRegionId(region.getRegionName(),region.getId());return result;}

3. 所以该方法适用于其余表字段修改较少的情况

三、分表预处理,前端再匹配

【场景说明】

前端还是需要展示一张涉及多张表数据的列表:

【实现方式】

这一次,我们后端同学不服了,凭啥老是让我们后端同学来处理这个问题,于是问题丢给了前端。前端如何实现这个需求呢?如果前端能像查字典一样匹配每张表的数据,然后组装在一起如何呢?显然可以。简单来说,前端预先分别调用多张列表的查询接口,将表数据预存到页面的响应式数据中形成字典,在进行v-for展示时,匹配字典,得到数据。这样一来,联表查询也被优化成单表查询了。

【实现步骤】

1. 预查询合作商表数据:

import {listPartner} from "@/api/manage/partner";
import {loadAllParams} from "@/api/page";// 定义
const partnerlist = ref([]);/** 查询合作商列表 */
function getPartnerList() {listPartner(loadAllParams).then(respone => {partnerlist.value = respone.rows;})
}// 使用
getPartnerList();

2. 预查询设备类型表:

import {listVmType} from "@/api/manage/vmType";
import {loadAllParams} from "@/api/page";// 定义
const vmTypeList = ref([]);/** 查询设备类型列表 */
function getVmTypeList() {listVmType(loadAllParams).then(respone => {vmTypeList.value = respone.rows;})
}// 使用
getVmTypeList();

3. 页面匹配调用:

<!--表格--><el-table v-loading="loading" :data="vmList" @selection-change="handleSelectionChange"><!--省略--><el-table-column label="设备型号" align="center" prop="vmTypeId"><!--字典--><template #default="scope"><div v-for="item in vmTypeList" :key="item.id"><span v-if="item.id == scope.row.vmTypeId">{{ item.name }}</span></div></template></el-table-column><el-table-column label="合作商" align="center" prop="partnerId"><!--字典--><template #default="scope"><div v-for="item in partnerlist" :key="item.id"><span v-if="item.id == scope.row.partnerId">{{ item.partnerName }}</span></div></template></el-table-column><!--省略--></el-table>

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

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

相关文章

鸿蒙网络编程系列32-基于拦截器的性能监控示例

1. 拦截器简介 在Web开发中拦截器是一种非常有用的模式&#xff0c;它允许开发者在请求发送到服务器之前或响应返回给客户端之前执行一些预处理或后处理操作。这种机制特别适用于需要对所有网络请求或响应进行统一处理的情况&#xff0c;比如添加全局错误处理、请求头的修改、…

PostgreSQL中触发器递归的处理 | 翻译

许多初学者在某个时候都会陷入触发器递归的陷阱。通常&#xff0c;解决方案是完全避免递归。但对于某些用例&#xff0c;您可能必须处理触发器递归。本文将告诉您有关该主题需要了解的内容。如果您曾经被错误消息“超出堆栈深度限制”所困扰&#xff0c;那么这里就是解决方案。…

电脑视频剪辑大比拼,谁更胜一筹?

随着短视频的火爆&#xff0c;越来越多的人开始尝试自己动手制作视频&#xff0c;无论是记录生活点滴还是创作个性短片&#xff0c;一款好用的视频剪辑软件是必不可少的。今天&#xff0c;我们就从短视频运营的角度&#xff0c;来聊聊几款热门的电脑视频剪辑软件&#xff0c;看…

FineReport 数据筛选过滤

从大量的数据当中&#xff0c;获取到符合条件的数据&#xff0c;经常会使用到数据筛选过滤功能&#xff0c;在FineReort产品中实现筛选过滤的方法有三种 1&#xff09;直接通过 SQL 语句取出满足条件的的数据&#xff0c;如修改数据集 SQL 语句为&#xff1a;SELECT * FROM 订单…

YOLOv8改进,YOLOv8采用WTConv卷积(感受野的小波卷积),二次创新C2f结构,ECCV 2024

摘要 WTConv(基于小波变换的卷积层),用于在卷积神经网络(CNN)中实现大感受野。作者通过利用小波变换,设计了一个卷积层,可以在保持少量可训练参数的情况下大幅扩大感受野。WTConv 被设计为可以无缝替换现有 CNN 架构中的深度卷积层,适用于图像分类、语义分割、物体检测…

Vue-插槽slot

当我们封装一个组件时&#xff0c;不希望里面的内容写死&#xff0c;希望使用的时候能够自定义里面的内容&#xff0c;这时我们就需要使用到插槽 插槽是什么呢 插槽是子组件提供给父组件的一个占位符&#xff0c;用slot标签表示&#xff0c;父组件可以在这个标签填写任何模板代…

3DMAX碎片生成器插件FragmentGenerator使用方法

3DMAX碎片生成器FragmentGenerator插件&#xff0c;主要应用于科研绘图方面&#xff0c;一键从选择对象体积上生成若干不规则大小凌乱排列的三角形面。 【适用版本】 3dMax2015 – 2025&#xff08;不仅限于此范围&#xff09; 【安装方法】 FragmentGenerator插件无需安装&a…

基于vue框架的的二手数码产品回收管理系统bodx1(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,产品分类,产品信息,预约回收,回收员,产品回收 开题报告内容 基于Vue框架的二手数码产品回收管理系统开题报告 一、课题背景及意义 随着科技的快速发展和消费者生活水平的提高&#xff0c;数码产品的更新换代速度日益加快&#x…

网络安全中的日志审计:为何至关重要?

在数字化时代&#xff0c;网络安全已成为企业和组织不可忽视的重要议题。随着网络攻击手段的不断进化&#xff0c;保护信息系统和数据安全变得日益复杂和具有挑战性。在这种背景下&#xff0c;日志审计作为一种关键的信息安全和网络管理工具&#xff0c;发挥着至关重要的作用。…

软考(网工)——局域网和城域网

文章目录 &#x1f550;局域网基础1️⃣局域网和城域网体系架构 IEEE&#xff08;负责链路层&#xff09;2️⃣局域网拓扑结构 &#x1f551;CSMA/CD1️⃣CSMA/CD2️⃣CSMA/CD三种监听算法3️⃣冲突检测原理 &#x1f552;二进制指数退避算法1️⃣ 二进制指数退避算法 &#x1…

envoyFilter导致的webSockets协议无法正常工作

一、背景 生产项目有一个socket请求经过网关一直无法响应&#xff0c;其它接口服务都能正常处理。 二、 处理过程 让租户提供对应的模拟请求接口&#xff0c;然后进行模拟请求测试&#xff0c;并查看envoy网关日志&#xff0c;发现在发起请求时&#xff0c;envoy网关日志是无法…

解密 Redis:如何通过 IO 多路复用征服高并发挑战!

文章目录 一、什么是 IO 多路复用&#xff1f;二、为什么 Redis 要使用 IO 多路复用&#xff1f;三、Redis 如何实现 IO 多路复用&#xff1f;四、IO 多路复用的核心机制&#xff1a;epoll五、IO 多路复用在 Redis 中的工作流程六、IO 多路复用的优点七、IO 多路复用使用中的注…

CTF(四)

导言&#xff1a; 本文主要讲述在CTF竞赛中&#xff0c;web类题目file_include。 靶场链接&#xff1a;攻防世界 (xctf.org.cn) 一&#xff0c;观察页面。 可以看到一段php代码。从则段代码中我们可以知道&#xff1a; 1&#xff0c;使用include引入check.php文件&#xff…

排序算法 —— 快速排序(理论+代码)

目录 1.快速排序的思想 2.快速排序的实现 hoare版 挖坑法 前后指针法 快排代码汇总 3.快速排序的优化 三数取中 小区间优化 三路划分 4.快速排序的非递归版本 5.快速排序总结 1.快速排序的思想 快速排序是一种类似于二叉树结构的排序方法。其基本思想为从待排序序…

【前端】如何制作一个自己的网页(15)

有关后代选择器的具体解释&#xff1a; 后代选择器 后代选择器使用时&#xff0c;需要以空格将多个选择器间隔开。 比如&#xff0c;这里p span&#xff0c;表示只设置p元素内&#xff0c;span元素的样式。 <style> /* 使用后代选择器设置样式 */ p span { …

给EXE添加网络验证激活码(卡密)

介绍 网络验证可以理解为给EXE文件添加一个激活码, 用户在打开EXE文件时, 需要输入激活码, 输入后, 通过网络验证激活码, 如果激活码有效用户便可以继续使用软件. 网络验证可以生成静态激活码(也就是卡密), 再需要使用的时候直接发给用户即可, 无需像离线一机一码加密那样需要…

漏洞挖掘 | 基于mssql数据库的sql注入

前记 今天挖edu随意点开个站&#xff0c;发现存在mssql数据库的sql注入&#xff0c;在此分享下整个挖掘过程 目录 0x1 判断网站数据库类型 0x2 了解mssql数据库的主要三大系统表 0x3 了解mssql的主要函数 0x4 判断注入点及其注入类型 0x5 联合查询之判断列数 0x6 联合查询之…

spring源码拓展点3之addBeanPostProcesser

概述 在refresh方法中的prepareBeanFactory方法中&#xff0c;有一个拓展点&#xff1a;addBeanPostProcessor。即通过注入Aware对象从而将容器中的某些值设置到某个bean中。 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));aware接口调用 …

华为配置 之 Console线路配置

目录 简介&#xff1a; 知识点&#xff1a; 配置Console线路密码 1.密码认证模式 2.AAA认证模式 知识点&#xff1a; 总结&#xff1a; 简介&#xff1a; 使用PC模拟器与路由器相连&#xff08;与交换机相连原理一样&#xff09;&#xff0c;在关机状态下&#xff0c;使用…

手机玩黑色沙漠?GameViewer远程玩黑色沙漠教程

黑色沙漠的国服即将在10月24日迎来公测&#xff01;这是一款玩法多元的大型多人在线角色扮演游戏&#xff0c;你可以享受激烈的战斗&#xff0c;也可以感受惬意的生活&#xff0c;在这个游戏里你能体验到一个不一样的冒险故事。不管你是老玩家还是新玩家&#xff0c;只要你想玩…