优化sql查询-使用element-ui实现懒查询(仅后端)

文章讲述了如何通过优化SQL查询和设计PO(PlainOldJavaObject)/VO(ViewObject)来提升地区页面搜索时数据响应的效率,从全表查询改为懒加载,减少初次加载时的数据量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在搜索地区页面时,优化数据的响应效果
原先业务逻辑为搜索所有的area表中的数据,使用sql查询找出子节点和父节点之间的关系

select t1.*, (select t2.area_name from sys_area t2 where t2.id = t1.pid) parentName from sys_area t1 where t1.deleted = 0

po和vo的设计如下,由于po与vo在数据交互的过程中会互相转化,所以需要让po和vo存在的字段一一对应,由于上级名称不存在与数据库表中,所以需要使用@TableField(exist = false)标记

//vo如下:
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "地区")
public class SysAreaVO extends TreeNode<SysAreaVO> {

    @Schema(description = "地区名称", required = true)
    @NotBlank(message = "地区名称不能为空")
    private String areaName;

    @Schema(description = "创建时间")
    @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
    private Date createTime;

    @Schema(description = "上级名称")
    private String parentName;
}

//po如下:
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_area")
public class SysAreaEntity extends BaseEntity {
    /**
     * 上级ID
     */
    private Long pid;
    /**
     * 地区编号
     */
    private String areaCode;
    /**
     * 地区名称
     */
    private String areaName;
    /**
     * 上级名称
     */
    @TableField(exist = false)
    private String parentName;

}

通过service层的方法调用tree的工具类,将表中的数据由扁平结构转化为树结构,再将树结构的数据响应给前端

//数据打包
public List<SysAreaVO> getList() {
        Map<String, Object> params = new HashMap<>();

        // 数据权限
        params.put(Constant.DATA_SCOPE, getDataScope("t1", "id"));

        // 机构列表
        List<SysAreaEntity> entityList = baseMapper.getList(params);

        //po转vo
        List<SysAreaVO> sysAreaVOS = BeanUtil.copyToList(entityList, SysAreaVO.class);
        //扁平化转树
        List<SysAreaVO> build = TreeUtils.build(sysAreaVOS);
        return build;
    }
  
//封装的工具类
public class TreeUtils {

    /**
     * 根据pid,构建树节点
     */
    public static <T extends TreeNode<T>> List<T> build(List<T> treeNodes, Long pid) {
        // pid不能为空
        AssertUtils.isNull(pid, "pid");

        List<T> treeList = new ArrayList<>();
        for (T treeNode : treeNodes) {
            if (pid.equals(treeNode.getPid())) {
                treeList.add(findChildren(treeNodes, treeNode));
            }
        }

        return treeList;
    }

    /**
     * 查找子节点
     */
    private static <T extends TreeNode<T>> T findChildren(List<T> treeNodes, T rootNode) {
        for (T treeNode : treeNodes) {
            if (rootNode.getId().equals(treeNode.getPid())) {
                rootNode.getChildren().add(findChildren(treeNodes, treeNode));
            }
        }
        return rootNode;
    }

    /**
     * 构建树节点
     */
    public static <T extends TreeNode<T>> List<T> build(List<T> treeNodes) {
        List<T> result = new ArrayList<>();

        // list转map
        Map<Long, T> nodeMap = new LinkedHashMap<>(treeNodes.size());
        for (T treeNode : treeNodes) {
            nodeMap.put(treeNode.getId(), treeNode);
        }

        for (T node : nodeMap.values()) {
            T parent = nodeMap.get(node.getPid());
            if (parent != null && !(node.getId().equals(parent.getId()))) {
                parent.getChildren().add(node);
                continue;
            }

            result.add(node);
        }

        return result;
    }

}

最后controller层接受请求,并且调用list方法,给前端响应树型的数据

@GetMapping("list")
    @Operation(summary = "列表")
    @PreAuthorize("hasAuthority('sys:area:list')")
    public Result<List<SysAreaVO>> list() {
        List<SysAreaVO> list = sysareaService.getList();

        return Result.ok(list);
    }

响应数据如下图所示:数据展示为一颗树,点击叶子节点不会再发送请求
在这里插入图片描述


但是上述业务逻辑有一个问题就是整表进行查询,在表中数据特别多的时候,首次进入页面的数据速度特别的慢


业务优化:使用懒查询解决一次性查找数据库表数据过慢的问题
对sql语句的优化

select t1.* ,(select t2.area_name from sys_area t2 where t2.id = t1.pid) as parentName from sys_area t1 where t1.deleted = 0 and t1.pid=#{pid}

vo和po修改后的代码,vo通过判断是否有子节点来进一步获取数据

//vo
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "地区")
public class SysAreaVO extends TreeNode<SysAreaVO> {

    @Schema(description = "地区名称", required = true)
    @NotBlank(message = "地区名称不能为空")
    private String areaName;

    @Schema(description = "创建时间")
    @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
    private Date createTime;

    @Schema(description = "上级名称")
    private String parentName;

    @Schema(description = "是否有子节点")
    private boolean hasChildren;

}

//po
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_area")
public class SysAreaEntity extends BaseEntity {
    /**
     * 上级ID
     */
    private Long pid;
    /**
     * 地区编号
     */
    private String areaCode;
    /**
     * 地区名称
     */
    private String areaName;
    /**
     * 上级名称
     */
    @TableField(exist = false)
    private String parentName;

}

service层的方法,getSubcount里的MyBatis-Plus和sql中的t1.pid=#{pid}相对应

//与原先一致
public List<SysAreaVO> getList(Long pid) {
        Map<String, Object> params = new HashMap<>();
        params.put("pid",pid);

        // 数据权限
        //params.put(Constant.DATA_SCOPE, getDataScope("t1", "id"));

        // 区域列表
        List<SysAreaEntity> entityList = baseMapper.getList(params);

        //po转vo
        List<SysAreaVO> sysAreaVOS = BeanUtil.copyToList(entityList, SysAreaVO.class);
        List<SysAreaVO> build = TreeUtils.build(sysAreaVOS);
        return build;
    }

//获取具有指定父ID的子实体数量
@Override
    public Long getSubcount(Long id){
       QueryWrapper<SysAreaEntity> queryWrapper = new QueryWrapper();
        queryWrapper.eq("pid",id);
        Long subcount=baseMapper.selectCount(queryWrapper);
        return  subcount;
    }

controller层的方法

@RestController
@RequestMapping("sys/area")
@Tag(name = "地区管理")
@AllArgsConstructor
public class SysAreaController {
    private final SysAreaService sysareaService;

    @GetMapping("list")
    @Operation(summary = "列表")
    @PreAuthorize("hasAuthority('sys:area:list')")
    public Result<List<SysAreaVO>> list(@RequestParam(value = "id",defaultValue = "86") Long id) {
        List<SysAreaVO> list = sysareaService.getList(id);
        list.forEach(e->{
        	//查询父级是否有子级
            Long subcount=sysareaService.getSubcount(id);
            if(subcount>0) {
            	//将vo的HasChildren置为true
                e.setHasChildren(true);
            }
            //因为后面我在sql中映射了,所以不用再单独查了
            //SysAreaEntity parentEntity = sysarseaService.getById(e.getPid());
            //e.setParentName(parentEntity.getAreaName());
        });
        return Result.ok(list);
    }

响应数据如下图所示:数据仅展示一级的所有叶子,点击某个叶子节点再次发送请求获得下一级的叶子

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拾雨_Rain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值