数据库单表查询,list分页关联展示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZZY1078689276/article/details/80546633

应用背景

  一般我们在开发数据量不是很大的中小型企业系统来说,直接使用SQL关联,多表联合查询就可以了,因为这样在项目开发过程中非常的高效。但是一旦在遇到大数据量的背景前提下,原始的关联查询方式逐渐的显现出了越来越多的弊端。

我们引入海尔电商技术总监Richie的观点来说,主要有以下几点:

从逻辑架构分层原则来看

  关联关系代表了业务规则/逻辑,毫无约束大量使用关联查询,就是把大量的业务规则和逻辑放在数据库来执行了,数据库消耗cpu、内存、io等资源进行关联操作,实际上是在做应用该做的事情。

从资源利用率方面看

  大部分场景下,并不是所有关联查询的结果都被有效使用了。例如后台管理的列表界面,通常都会分页显示,关联查询的结果集,只有当前页的数据被使用,其他都是无用的,但数据库需要消耗额外资源得到全部结果集,再从中得到当前页数据。

从架构的伸缩性方面看

  大量的关联查询会导致集中式的数据库架构很难向分布式架构转换,伸缩性方面的优化难度高。

总结:

  关联查询方便快速,开发效率比较好,如果系统、数据库经过一些垂直优化手段完全能够满足性能要求是可以使用的,例如中小企业的内部管理系统等。

  不使用关联查询在架构层面有很多优点,但对系统分析和设计、开发能力要求高。一般在互联网行业等用户数较多的情况下最好重视这方面。

  理论上不存在什么复杂场景,如果不使用数据库的关联查询就无法满足需求的。巨无霸的ERP系统SAP,基本整个系统功能都是用单表查询实现的。

代码实现

  从前面的介绍中我们了解到,很多高性能的应用都会对关联查询进行分解。简单的来说,可以对每一个表进行一次单表查询,然后将结果在应用程序中进行关联。

  比如说下面截图中的数据就是利用这种原理实现的。

这里写图片描述

  下面我以实际的代码为例来进行说明,其中由于数据均为模拟数据,所以说我直接通过手写的方式代替数据库查询来给结果集进行赋值。

  • join()实现多表关联
  • filter()实现where查询
  • listPage()实现数据分页功能。

实体类

Class

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class Class {

    private String id;
    private String name;

}

Student

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class Student {

    private String id;
    private String name;
    private String classId;

}

PageQuery

import com.google.common.collect.Lists;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@ApiModel(value = "PageQuery",description = "这个是分页查询实体类",subTypes = PageQuery.class)
public class PageQuery<T> {

    //页数
    @ApiModelProperty(name = "page",value = "页数索引",notes = "请求的页数",required = true)
    private int page;
    //每页显示的信息数
    @ApiModelProperty(name = "limit",value = "信息条数",notes = "每页展示的信息条数",required = true)
    private int limit;
    //开始坐标
    @ApiModelProperty(name = "start",value = "sql查询起始页",notes = "开始坐标")
    private int start;
    //截止坐标
    @ApiModelProperty(name = "end",value = "list截取截止坐标",notes = "截止坐标")
    private int end;

    public PageQuery(int page, int limit){
        this.start = (page - 1) * limit;
        this.limit = limit;
        this.end = this.start + this.limit;
    }

    /**
     * list数组分页
     * @param list
     * @return
     */
    public List<T> getListPage(List<T> list){
        List<T> subedList = null;
        //如果list数组长度大于开始坐标,则有效,否则返回空数组。
        if(list.size() >= this.start){
            //如果list数组的长度小于等于截止坐标,则list索引值有可能会越界,故此时的最终list索引值应该修正为数组的长度
            if(list.size() <= end){
                subedList = list.subList(this.start,list.size());
            } else {   //如果list数组的长度大于截止坐标,则list索引值始终有效,此时最终list索引值应该为截止坐标
                subedList = list.subList(this.start,this.end);
            }
            //返回截取的数组
            return subedList;
        }
        return Lists.newArrayList();
    }

}

ClassStudentDTO

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@Builder
@ToString
public class ClassStudentDTO {

    private String id;
    private String studentId;
    private String classId;
    private String className;
    private String studentName;

}

测试代码

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.mysql.cj.core.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;

import java.util.List;
import java.util.Map;

@Slf4j
public class ListPageTest {

    private List<Class> classList = Lists.newArrayList();
    private List<Student> studentList = Lists.newArrayList();

    /**
     * 初始化班级,学生信息
     */
    @Before
    public void initDB(){
        for(int i = 1;i <= 3;i ++){
            Class clazz = Class.builder()
                    .id(StringUtils.getUniqueSavepointId())
                    .name("班级" + i)
                    .build();
            classList.add(clazz);
            for(int j = 1;j <= 3;j ++){
                Student student = Student.builder()
                        .id(StringUtils.getUniqueSavepointId())
                        .name("学生" + i + j)
                        .classId(clazz.getId())
                        .build();
                studentList.add(student);
            }
        }
    }

    /**
     * 测试分页
     */
    @Test
    public void test(){
        //连接表
        List<ClassStudentDTO> joinedTable = join(classList,studentList);
        //假设传入的查询条件是“班级2”
        //查找目标班级数据
        List<Class> searchedClasses = getSearchedClass("班级2");
        //过滤表
        List<ClassStudentDTO> searchedClassStudentDTO = filter(joinedTable,searchedClasses);
        //假设前台传入的查询分页信息为:第二页,每页显示2条数据
        PageQuery pageQuery = new PageQuery(1,2);
        //list分页
        List<ClassStudentDTO> pagedList = listPage(searchedClassStudentDTO,pageQuery);
        log.info("信息总条数为:{}",searchedClassStudentDTO.size());
        log.info("查询的内容:");
        //查询的内容
        pagedList.forEach(classStudentDTO -> log.info(classStudentDTO.toString()));
    }

    /**
     * 连接表
     * @param classList
     * @param studentList
     * @return
     */
    private List<ClassStudentDTO> join(List<Class> classList,List<Student> studentList){
        Map<String,Class> classMap = Maps.newHashMap();
        classList.forEach(clazz -> {
            classMap.put(clazz.getId(),clazz);
        });
        List<ClassStudentDTO> classStudentDTOS = Lists.newArrayList();
        studentList.forEach(student -> {
            ClassStudentDTO classStudentDTO = ClassStudentDTO.builder()
                    .id(StringUtils.getUniqueSavepointId())
                    .studentId(student.getId())
                    .classId(student.getClassId())
                    .className(classMap.get(student.getClassId()).getName())
                    .studentName(student.getName())
                    .build();
            classStudentDTOS.add(classStudentDTO);
        });
        return classStudentDTOS;
    }

    /**
     * 查找目标班级数据
     * @param className
     * @return
     */
    private List<Class> getSearchedClass(String className){
        List<Class> searchedClasses = Lists.newArrayList();
        classList.forEach(clazz -> {
            if(clazz.getName().equals(className)){
                searchedClasses.add(clazz);
            }
        });
        return searchedClasses;
    }

    /**
     * 过滤数据
     * @param joinedTable
     * @param searchedClasses
     * @return
     */
    private List<ClassStudentDTO> filter(List<ClassStudentDTO> joinedTable,List<Class> searchedClasses){
        List<ClassStudentDTO> searchedClassStudentDTO = Lists.newArrayList();
        Multimap<String,ClassStudentDTO> multimap = ArrayListMultimap.create();
        joinedTable.forEach(classStudentDTO -> {
            multimap.put(classStudentDTO.getClassId(),classStudentDTO);
        });
        searchedClasses.forEach(searchedClass -> {
            List<ClassStudentDTO> dtos = (List<ClassStudentDTO>) multimap.get(searchedClass.getId());
            searchedClassStudentDTO.addAll(dtos);
        });
        return searchedClassStudentDTO;
    }

    /**
     * list分页
     * @param searchedClassStudentDTO
     * @param pageQuery
     * @return
     */
    private List<ClassStudentDTO> listPage(List<ClassStudentDTO> searchedClassStudentDTO,PageQuery pageQuery){
        return pageQuery.getListPage(searchedClassStudentDTO);
    }

}

测试结果

[13:05:32.571] INFO  com.baishun.login.listPage.ListPageTest 60 test - 信息总条数为:3
[13:05:32.581] INFO  com.baishun.login.listPage.ListPageTest 61 test - 查询的内容:
[13:05:32.582] INFO  com.baishun.login.listPage.ListPageTest 63 lambda$test$0 - ClassStudentDTO(id=cff92128_902a_471f_ad67_d75427d17006, studentId=6a673faa_0e62_4081_9cb4_1719489cfce6, classId=acc94722_e24a_4a11_b632_d23d9c5eddc8, className=班级2, studentName=学生21)
[13:05:32.583] INFO  com.baishun.login.listPage.ListPageTest 63 lambda$test$0 - ClassStudentDTO(id=93600c44_2dd1_49c1_b903_1fb585822edd, studentId=d41caa65_dae2_48b6_b6e8_166f498a7ae3, classId=acc94722_e24a_4a11_b632_d23d9c5eddc8, className=班级2, studentName=学生22)

猜你喜欢

转载自blog.csdn.net/ZZY1078689276/article/details/80546633