MybatisPlus多表连接查询

Mybatis巧用@One注解一个SQL联合查询语句实现一对一查询 阅读详情

一、序言

(一)背景内容

软件应用技术架构中DAO层最常见的选型组件为MyBatis,熟悉MyBatis的朋友都清楚,曾几何时MyBatis是多么的风光,使用XML文件解决了复杂的数据库访问的难题。时至今日,曾经的屠龙者终成恶龙,以XML文件为基础的数据库访问技术变得臃肿、复杂,维护难度直线上升。

MybatisPlus对常见的数据库访问进行了封装,访问数据库大大减少了XML文件的依赖,开发者从臃肿的XML文件中获得了较大限度的解脱。

MybatisPlus官方并没有提供多表连接查询的通用解决方案,然而连接查询是相当普遍的需求。解决连接查询有两种需求,一种是继续使用MyBatis提供XML文件解决方式;另一种本文提供的解决方案。

事实上笔者强烈推荐彻底告别通过XML访问数据库,并不断探索新式更加友好、更加自然的解决方式,现分享最新的MybatisPlus技术的研究成果。

image-20211021114957682

(二)场景说明

为了说明连接查询的关系,这里以学生、课程及其关系为示例。

image-20211020194255298

(三)前期准备

此部分需要读者掌握以下内容:Lambda 表达式、特别是方法引用;函数式接口;流式运算等等,否则理解起来会有些吃力。

image-20211021135113431

实体类与 Vo 的映射关系,作者创造性的引入特别构造器,合理利用继承关系,极大的方便了开发者完成实体类向 Vo 的转换。

空指针异常忽略不处理,借助Optional类实现,详情移步Java8 新特性查看。

二、一对一查询

一对一查询最典型的应用场景是将id替换成name,比如将userId替换成userName。

(一)查询单条记录

查询单条记录是指返回值仅有一条记录,通常是以唯一索引作为条件的返回查询结果。

1、示例代码
/**
 * 查询单个学生信息(一个学生对应一个部门)
 */
public UserVo getOneUser(Integer userId) {
    LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
        .eq(User::getUserId, userId);
    // 先查询用户信息
    User user = userMapper.selectOne(wrapper);
    // 转化为Vo
    UserVo userVo = Optional.ofNullable(user).map(UserVo::new).orElse(null);
    // 从其它表查询信息再封装到Vo
    Optional.ofNullable(userVo).ifPresent(this::addDetpNameInfo);
    return userVo;
}

附属表信息补充

/**
 * 补充部门名称信息
 */
private void addDetpNameInfo(UserVo userVo) {
    LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class)
        .eq(Dept::getDeptId, userVo.getDeptId());
    Dept dept = deptMapper.selectOne(wrapper);
    Optional.ofNullable(dept).ifPresent(e -> userVo.setDeptName(e.getDeptName()));
}
2、理论分析

查询单个实体共分为两个步骤:根据条件查询主表数据(需处理空指针异常);封装 Vo 并查询附属表数据。

查询结果(VO)只有一条记录,需要查询两次数据库,时间复杂度为O(1)。

(二)查询多条记录

查询多条记录是指查询结果为列表,通常是指以普通索引为条件的查询结果。

1、示例代码
/**
 * 批量查询学生信息(一个学生对应一个部门)
 */
public List<UserVo> getUserByList() {
    // 先查询用户信息(表现形式为列表)
    List<User> user = userMapper.selectList(Wrappers.emptyWrapper());
    List<UserVo> userVos = user.stream().map(UserVo::new).collect(toList());
    // 此步骤可以有多个
    addDeptNameInfo(userVos);
    return userVos;
}

附属信息补充

private void addDeptNameInfo(List<UserVo> userVos) {
    // 提取用户userId,方便批量查询
    Set<Integer> deptIds = userVos.stream().map(User::getDeptId).collect(toSet());
    // 根据deptId查询deptName(查询前,先做非空判断)
    List<Dept> dept = deptMapper.selectList(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
    // 构造映射关系,方便匹配deptId与deptName
    Map<Integer, String> hashMap = dept.stream().collect(toMap(Dept::getDeptId, Dept::getDeptName));
    // 封装Vo,并添加到集合中(关键内容)
    userVos.forEach(e -> e.setDeptName(hashMap.get(e.getDeptId())));
}
2、理论分析

先查询包含id的列表记录,从结果集中析出id并转化成批查询语句再访问数据库,从第二次调用结果集中解析出name。

查询结果(VO)有多条记录,但仅调用两次数据库,时间复杂度为O(1)。

(三)查询多条记录(分页)

分页查询实体的思路与查询列表的思路相似,额外多处一步分页泛型转换。

1、示例代码
/**
 * 分页查询学生信息(一个学生对应一个部门)
 */
public IPage<UserVo> getUserByPage(Page<User> page) {
    // 先查询用户信息
    IPage<User> xUserPage = userMapper.selectPage(page, Wrappers.emptyWrapper());
    // 初始化Vo
    IPage<UserVo> userVoPage = xUserPage.convert(UserVo::new);
    if (userVoPage.getRecords().size() > 0) {
        addDeptNameInfo(userVoPage);
    }
    return userVoPage;
}

查询补充信息

private void addDeptNameInfo(IPage<UserVo> userVoPage) {
    // 提取用户userId,方便批量查询
    Set<Integer> deptIds = userVoPage.getRecords().stream().map(User::getDeptId).collect(toSet());
    // 根据deptId查询deptName
    List<Dept> dept = deptMapper.selectList(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
    // 构造映射关系,方便匹配deptId与deptName
    Map<Integer, String> hashMap = dept.stream().collect(toMap(Dept::getDeptId, Dept::getDeptName));
    // 将查询补充的信息添加到Vo中
    userVoPage.convert(e -> e.setDeptName(hashMap.get(e.getDeptId())));
}

IPage接口中convert方法,能够实现在原实例上修改。

2、理论分析

先查询包含id的列表记录,从结果集中析出id并转化成批查询语句再访问数据库,从第二次调用结果集中解析出name。

查询结果(VO)有多条记录,但仅调用两次数据库,时间复杂度为O(1)。

三、一对多查询

一对多查询最常见的场景是查询部门所包含的学生信息,由于一个部门对应多个学生,每个学生对应一个部门,因此称为一对多查询。

(一)查询单条记录
1、示例代码
/**
 * 查询单个部门(其中一个部门有多个用户)
 */
public DeptVo getOneDept(Integer deptId) {
    // 查询部门基础信息
    LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class).eq(Dept::getDeptId, deptId);
    DeptVo deptVo = Optional.ofNullable(deptMapper.selectOne(wrapper)).map(DeptVo::new).orElse(null);
    Optional.ofNullable(deptVo).ifPresent(this::addUserInfo);
    return deptVo;
}

补充附加信息

private void addUserInfo(DeptVo deptVo) {
    // 根据部门deptId查询学生列表
    LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).eq(User::getDeptId, deptVo.getDeptId());
    List<User> users = userMapper.selectList(wrapper);
    deptVo.setUsers(users);
}
2、理论分析

整个过程共分为两个阶段:通过部门表中主键查询指定部门信息,通过学生表中部门ID外键查询学生信息,将结果合并,形成返回值(Vo)。

一对多查询单条记录整个过程至多需要调用2次数据库查询,查询次数为常数,查询时间复杂度为O(1)。

(二)查询多条记录
1、示例代码
/**
 * 查询多个部门(其中一个部门有多个用户)
 */
public List<DeptVo> getDeptByList() {
    // 按条件查询部门信息
    List<Dept> deptList = deptMapper.selectList(Wrappers.emptyWrapper());
    List<DeptVo> deptVos = deptList.stream().map(DeptVo::new).collect(toList());
    if (deptVos.size() > 0) {
        addUserInfo(deptVos);
    }
    return deptVos;
}

补充附加信息

private void addUserInfo(List<DeptVo> deptVos) {
    // 准备deptId方便批量查询用户信息
    Set<Integer> deptIds = deptVos.stream().map(Dept::getDeptId).collect(toSet());
    // 用批量deptId查询用户信息
    List<User> users = userMapper.selectList(Wrappers.lambdaQuery(User.class).in(User::getDeptId, deptIds));
    // 重点:将用户按照deptId分组
    Map<Integer, List<User>> hashMap = users.stream().collect(groupingBy(User::getDeptId));
    // 合并结果,构造Vo,添加集合列表
    deptVos.forEach(e -> e.setUsers(hashMap.get(e.getDeptId())));
}
2、理论分析

整个过程共分为三个阶段:通过普通索引从部门表中查询若干条记录;将部门ID转化为批查询从学生表中查询学生记录;将学生记录以部门ID为单位进行分组,合并结果,转化为Vo。

一对多查询多条记录需要调用2次数据库查询,查询次数为常数,查询时间复杂度为O(1)。

(三)查询多条记录(分页)
1、示例代码
/**
 * 分页查询部门信息(其中一个部门有多个用户)
 */
public IPage<DeptVo> getDeptByPage(Page<Dept> page) {
    // 按条件查询部门信息
    IPage<Dept> xDeptPage = deptMapper.selectPage(page, Wrappers.emptyWrapper());
    IPage<DeptVo> deptVoPage = xDeptPage.convert(DeptVo::new);
    if (deptVoPage.getRecords().size() > 0) {
        addUserInfo(deptVoPage);
    }
    return deptVoPage;
}

查询补充信息

private void addUserInfo(IPage<DeptVo> deptVoPage) {
    // 准备deptId方便批量查询用户信息
    Set<Integer> deptIds = deptVoPage.getRecords().stream().map(Dept::getDeptId).collect(toSet());
    LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).in(User::getDeptId, deptIds);
    // 用批量deptId查询用户信息
    List<User> users = userMapper.selectList(wrapper);
    // 重点:将用户按照deptId分组
    Map<Integer, List<User>> hashMap = users.stream().collect(groupingBy(User::getDeptId));
    // 合并结果,构造Vo,添加集合列表
    deptVoPage.convert(e -> e.setUsers(hashMap.get(e.getDeptId())));
}
2、理论分析

整个过程共分为三个阶段:通过普通索引从部门表中查询若干条记录;将部门ID转化为批查询从学生表中查询学生记录;将学生记录以部门ID为单位进行分组,合并结果,转化为Vo。

一对多查询多条记录需要调用2次数据库查询,查询次数为常数,查询时间复杂度为O(1)。

四、多对多查询

MybatisPlus 实现多对多查询是一件极富挑战性的任务,也是连接查询中最困难的部分。

以空间置换时间,借助于流式运算,解决多对多查询难题。

多对多查询相对于一对多查询,增加了流式分组运算、批量 HashMap 取值等内容。

image-20211024115903848

(一)查询单条记录

查询单条记录一般是指通过两个查询条件查询出一条匹配表中的记录。

1、示例代码
public StudentVo getStudent(Integer stuId) {
    // 通过主键查询学生信息
    StudentVo studentVo = ConvertUtils.convertObj(getById(stuId), StudentVo::new);
    LambdaQueryWrapper<StuSubRelation> wrapper = Wrappers.lambdaQuery(StuSubRelation.class).eq(StuSubRelation::getStuId, stuId);
    // 查询匹配关系
    List<StuSubRelation> stuSubRelations = stuSubRelationMapper.selectList(wrapper);
    Set<Integer> subIds = stuSubRelations.stream().map(StuSubRelation::getSubId).collect(toSet());
    if (studentVo != null && subIds.size() > 0) {
        List<Subject> subList = subjectMapper.selectList(Wrappers.lambdaQuery(Subject.class).in(Subject::getId, subIds));
        List<SubjectBo> subBoList = ConvertUtils.convertList(subList, SubjectBo::new);
        HashBasedTable<Integer, Integer, Integer> table = getHashBasedTable(stuSubRelations);
        subBoList.forEach(e -> e.setScore(table.get(stuId, e.getId())));
        studentVo.setSubList(subBoList);
    }
    return studentVo;
}
2、理论分析

多对多单条记录查询最多访问数据库3次,先查询学生信息,然后查询学生与课程匹配信息,最后查询课程分数信息,查询时间复杂度为O(1)。

(二)查询多条记录
1、示例代码
public List<StudentVo> getStudentList() {
    // 通过主键查询学生信息
    List<StudentVo> studentVoList = ConvertUtils.convertList(list(), StudentVo::new);
    // 批量查询学生ID
    Set<Integer> stuIds = studentVoList.stream().map(Student::getId).collect(toSet());
    LambdaQueryWrapper<StuSubRelation> wrapper = Wrappers.lambdaQuery(StuSubRelation.class).in(StuSubRelation::getStuId, stuIds);
    List<StuSubRelation> stuSubRelations = stuSubRelationMapper.selectList(wrapper);
    // 批量查询课程ID
    Set<Integer> subIds = stuSubRelations.stream().map(StuSubRelation::getSubId).collect(toSet());
    if (stuIds.size() > 0 && subIds.size() > 0) {
        HashBasedTable<Integer, Integer, Integer> table = getHashBasedTable(stuSubRelations);
        List<Subject> subList = subjectMapper.selectList(Wrappers.lambdaQuery(Subject.class).in(Subject::getId, subIds));
        List<SubjectBo> subjectBoList = ConvertUtils.convertList(subList, SubjectBo::new);
        Map<Integer, List<Integer>> map = stuSubRelations.stream().collect(groupingBy(StuSubRelation::getStuId, mapping(StuSubRelation::getSubId, toList())));
        for (StudentVo studentVo : studentVoList) {
            // 获取课程列表
            List<SubjectBo> list = ListUtils.select(subjectBoList, e -> emptyIfNull(map.get(studentVo.getId())).contains(e.getId()));
            // 填充分数
            list.forEach(e -> e.setScore(table.get(studentVo.getId(), e.getId())));
            studentVo.setSubList(list);
        }
    }
    return studentVoList;
}
2、理论分析

多对多N条记录查询由于使用了批查询,因此最多访问数据库也是3次,先查询学生信息,然后查询学生与课程匹配信息,最后查询课程分数信息,查询时间复杂度为O(1)。

(三)查询多条记录(分页)
1、示例代码
public IPage<StudentVo> getStudentPage(IPage<Student> page) {
    // 通过主键查询学生信息
    IPage<StudentVo> studentVoPage = ConvertUtils.convertPage(page(page), StudentVo::new);
    // 批量查询学生ID
    Set<Integer> stuIds = studentVoPage.getRecords().stream().map(Student::getId).collect(toSet());
    LambdaQueryWrapper<StuSubRelation> wrapper = Wrappers.lambdaQuery(StuSubRelation.class).in(StuSubRelation::getStuId, stuIds);
    // 通过学生ID查询课程分数
    List<StuSubRelation> stuSubRelations = stuSubRelationMapper.selectList(wrapper);
    // 批量查询课程ID
    Set<Integer> subIds = stuSubRelations.stream().map(StuSubRelation::getSubId).collect(toSet());
    if (stuIds.size() > 0 && subIds.size() > 0) {
        HashBasedTable<Integer, Integer, Integer> table = getHashBasedTable(stuSubRelations);
        // 学生ID查询课程ID组
        Map<Integer, List<Integer>> map = stuSubRelations.stream().collect(groupingBy(StuSubRelation::getStuId, mapping(StuSubRelation::getSubId, toList())));

        List<Subject> subList = subjectMapper.selectList(Wrappers.lambdaQuery(Subject.class).in(Subject::getId, subIds));
        List<SubjectBo> subBoList = ConvertUtils.convertList(subList, SubjectBo::new);
        for (StudentVo studentVo : studentVoPage.getRecords()) {
            List<SubjectBo> list = ListUtils.select(subBoList, e -> emptyIfNull(map.get(studentVo.getId())).contains(e.getId()));
            list.forEach(e -> e.setScore(table.get(studentVo.getId(), e.getId())));
            studentVo.setSubList(list);
        }
    }
    return studentVoPage;
}
2、理论分析

多对多N条记录分页查询由于使用了批查询,因此最多访问数据库也是3次,先查询学生信息,然后查询学生与课程匹配信息,最后查询课程分数信息,查询时间复杂度为O(1)。

五、总结与拓展

(一)总结

通过上述分析,能够用 MybatisPlus 解决多表连接查询中的一对一、一对多、多对多查询。

  • 上述代码行文紧凑,充分利用 IDE 对 Lambda 表达式的支持,在编译期间完成对代码的检查。
  • 业务逻辑清晰,可维护性、可修改性优势明显。
  • 一次查询需要访问至多两次数据库,时间复杂度为o(1),主键查询或者索引查询,查询效率高。
(二)拓展

MybatisPlus能很好的解决单表查询问题,同时借助在单表查询的封装能很好地解决连接查询问题。

本方案不仅解决了连接查询问题,同时具备如下内容拓展:

  • 当数据量较大时,仍然具有稳定的查询效率

当数据量达到百万级别时,传统的单表通过索引查询已经面临挑战,普通的多表连接查询性能随着数据量的递增呈现指数级下降。

本方案通过将连接查询转化为主键(索引)查询,查询性能等效于单表查询。

  • 与二级缓存配合使用进一步提高查询效率

当所有的查询均转化为以单表为基础的查询后,方能安全的引入二级缓存。二级缓存的单表增删改查操作自适应联动,解决了二级缓存的脏数据问题。


喜欢本文点个赞支持一下,如有需要,可通过微信dream4s与我联系。相关源码在GitHub,视频讲解在B站,本文收藏在博客天地。


先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

mybatis-plus-join,一个可以让mybatis-plus实现联表的插件 注意:这几个方法,前面俩参数和mp的用法一致,最后一个class类型的是返回类型,这个主要是大多数多表操作都是需要有额外字段,所以需要额外定义,而Wrapper wrapper中的这个需要填写在需要构建条件的实体,这个实体是任意的,不强制,创建条件构造器的时候定义的那个对象就是主表。2.这个条件构造器啊,你在join的时候就相当于创建一个新的构造器,你要在这个新的构造器中实现你所有的操作,包括查询,和条件,排序之类的,这样的好处在于,维护好一些,毕竟都放在一起的话,到时候容易迷。 阅读详情

相关推荐

使用MybatisPlus实现多表联查

JavaBean代码 Department 类 package com.refactor.demo.entities; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import l...

weixin_44261816的博客 2970

MybatisPlus联合查询

目录1、什么是Mybatis-plus-join?2、下载Mybatis-plus-join3、离线版请使用Maven将其打包成jar包3.1、使用idea打包4.项目中引用Mybatis-plus-join的pom.xml配置5、在业务中使用mybatis-plus-join的准备使用核心类 MPJLambdaWrapper和MPJQueryWrapperMPJLambdaWrapper用法MPJLambdaWrapper示例简单的3表查询分页查询MPJQueryWrapper简单的3表查询分页查询还可以

赵广陆 3万+

MybatisPlus多表连接查询一对多分页查询数据

在日常一线开发过程中,多表连接查询不可或缺,基于MybatisPlus多表连接查询究竟该如何实现,本文将带你找到答案。

Java知识图谱的博客 3074

Mybatis多表联查的几种办法

开发过程中,对数据库多表连接查询是常规操作。Mybatis(plus)在多表连接查询上提供了很好的支持。通常,表与表之间存在四种映射关系:一对一映射、多对一映射、一对多映射、多对多映射。在处理的过程中,多对一和一对一映射一般采用同一种操作方式,一对多和多对多映射一般采用同一种操作方式。而且,对于Mybatis的运用,我们通常使用xml的方式。因此,本文主要介绍xml方式下一对一多表联查和一对多多表联查。

weixin_51667449的博客 2万+

基于OpenCV的围棋终局识别与胜负判定系统实现

计算机视觉是人工智能领域的关键技术,它使计算机能够从数字图像或视频中获取、处理和分析信息。其核心原理在于通过图像处理算法提取特征,并基于这些特征进行识别、分类和测量。在工程实践中,计算机视觉技术为自动化、智能化应用提供了强大支持,广泛应用于工业检测、自动驾驶、医疗影像分析等领域。本文聚焦于一个具体的应用场景:利用OpenCV库实现围棋终局识别。通过图像预处理、棋盘检测与透视校正、交叉点定位等步骤,结合围棋规则逻辑,构建了一套从棋盘图像自动判定胜负的解决方案。该方案涉及自适应二值化、霍夫变换、连通域分析等关键

weixin_29100927的博客 280

从UE4到Unity:双叶高光技术在角色皮肤渲染中的移植全流程

本文详细解析了将UE4中的双叶高光技术移植到Unity引擎的全流程。该技术通过模拟皮肤油脂层和真皮层的不同反射特性,能显著提升角色皮肤渲染的真实感。文章从核心原理、贴图资产处理、Shader代码重构到参数调校,提供了完整的跨引擎移植实战指南,帮助开发者实现高质量的皮肤质感还原。

alice7model的博客 479

深入解析MybatisPlus多表连接查询

多对多N条记录查询由于使用了批查询,因此最多访问数据库也是3次,先查询学生信息,然后查询学生与课程匹配信息,最后查询课程分数信息,查询时间复杂度为O(1)。多对多单条记录查询最多访问数据库3次,先查询学生信息,然后查询学生与课程匹配信息,最后查询课程分数信息,查询时间复杂度为O(1)。一对多查询最常见的场景是查询部门所包含的学生信息,由于一个部门对应多个学生,每个学生对应一个部门,因此称为一对多查询。通过上述分析,能够用 MybatisPlus 解决多表连接查询中的一对一、一对多、多对多查询。

chinaherolts2008的博客 1301

Kali使用Metasploit内、外网渗透windows系统

Metasploit是一个免费的、可下载的框架,通过它可以很容易地获取、开发并对计算机软件漏洞实施攻击。它本身附带数百个已知软件漏洞的专业级漏洞攻击工具。当H.D. Moore在2003年发布Metasploit时,计算机安全状况也被永久性地改变了。 一、(内网渗透)内网英文缩写WAN;内网又称局域网 局域网的覆盖范围一般是方圆几千米之内,其具备的安装便捷、成本节约、扩展方便等特点使其在各类办公室内运用广泛。局域网可以实现文件管理、应用软件共享、打印机共享等功能,在使用过程当中,通过维护局域网网...

QQ670663的博客 2万+

深入解析MybatisPlus多表连接查询实践

通过上述分析,能够用 MybatisPlus 解决多表连接查询中的一对一一对多多对多查询。上述代码行文紧凑,充分利用 IDE 对 Lambda 表达式的支持,在编译期间完成对代码的检查。业务逻辑清晰,可维护性、可修改性优势明显。一次查询需要访问至多两次数据库,时间复杂度为o(1),主键查询或者索引查询,查询效率高。

Da_zhenzai的博客 1万+

DSP28335新手避坑指南:手把手教你用CCS6.2生成10KHz SPWM(附完整工程)

本文详细介绍了如何使用DSP28335开发板和CCS6.2环境生成10KHz SPWM波形的完整工程指南。从开发环境配置、ePWM模块设置到SPWM算法实现,特别针对新手常见问题提供了解决方案和调试技巧,帮助工程师快速掌握DSP28335的SPWM生成技术。

weixin_42522374的博客 182

Spring WebFlux响应式编程实战(三):优雅处理异常与高效调试技巧

本文深入探讨了Spring WebFlux响应式编程中的异常处理与调试技巧。文章通过电商订单流处理场景,详细解析了Reactor核心操作符onErrorReturn、onErrorResume和onErrorMap的实战应用,并介绍了如何构建@ControllerAdvice和WebExceptionHandler全局异常处理防线。同时,提供了使用.log()操作符、Hooks.onOperatorDebug()及BlockHound进行高效调试的方法,旨在帮助开发者构建健壮、可维护的响应式应用。

weixin_29252171的博客 67

MybatisPlus多表连接查询 支持一对一、一对对、多对多查询

一、序言 (一)背景内容 软件应用技术架构中DAO层最常见的选型组件为MyBatis,熟悉MyBatis的朋友都清楚,曾几何时MyBatis是多么的风光,使用XML文件解决了复杂的数据库访问的难题。时至今日,曾经的屠龙者终成恶龙,以XML文件为基础的数据库访问技术变得臃肿、复杂,维护难度直线上升。 MybatisPlus对常见的数据库访问进行了封装,访问数据库大大减少了XML文件的依赖,开发者从臃肿的XML文件中获得了较大限度的解脱。 MybatisPlus官方并没有提供多表连接查询的通用解决方案,然而连接

m0_66876551的博客 5689

Kriging代理模型理论相关推导

代理模型,Kriging,加点准则

森屹的博客 1万+

MyBatisPlus实现自定义分页查询数据结合QueryWrapper实现自定义的多表连接查询

在MyBatisPlus中,虽然框架自带的BaseMapper具有各种CRUD操作,但有时需要进行自定义的查询,如多表的连接查询: 首先准备实体类: @Data public class Dish implements Serializable { private static final long serialVersionUID = 1L; private Long id; //菜品名称 private String name; //菜品分类id

dames的博客 3950

3. 动手运行第一个 SAP Fiori Elements 应用(ListReport 类型)

这个代理服务器能够自动监听我们 Fiori Elements 应用里向 ES5 Demo 系统发送的 OData 请求,拦截这个请求,并通过 Node.js 代码向 ES5 服务器转发,拿到响应数据后再交还给 Fiori Elements 应用。后者对自己发出的请求被代理这件事情一无所知。本文的任务是,大家按照我的介绍,在本地成功运行笔者准备的这个 Fiori Elements 应用。的错误消息, 说明大家安装的 Node.js 版本没有达到本地运行 Fiori Elements 的最低要求。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1671

claude code desktop中出现Doesn‘t look like an Anthropic model - expected a gateway model route 解决方案

本文主要介绍了claude code desktop中出现Doesn’t look like an Anthropic model - expected a gateway model route referencing an Anthropic model和Server is busy. Retrying的解决方案,希望能对使用claude code desktop的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 9万+

mybatisplus多表关联查询_神奇的SQL:探索多表连接查询的执行细节

作者:jb_hz先构建本篇博客的案列演示表:1.驱动表如何选择?驱动表的概念是指多表关联查询时,第一个被处理的表,使用此表的记录去关联其他表。驱动表的确定很关键,会直接影响多表连接的关联顺序,也决定了后续关联时的查询性能。驱动表的选择遵循一个原则:在对最终结果集没影响的前提下,优先选择结果集最小的那张表作为驱动表。改变驱动表就意味着改变连接顺序,只有在不会改变最终输出结果的前提下才可以对驱动表做优...

weixin_39587029的博客 1625

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

mybatisPlus 使用mapper多表多连接查询

这个问题花了我3个小时,。先上图,以后再解释 &lt;select id="getComJob" parameterType="List" resultType="hashMap"&gt; select job.*, jobclass1.name as catname1, jobclass2.name as catname2, jobclass3.name as catna...

六一首席 3万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

mybatisPlus实现多表连接分页动态查询

【代码】mybatisPlus实现多表连接分页动态查询。

gp_911014的博客 1449

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

mybatisplus多表关联查询_ET工具_KETTLE多表关联

以下操作都在5.0.1版本下进行开发,其余版本可以进行自动比对在平时工作当中,会遇到这种情况,而且很常见。比如:读取对方的多个视图或者表,写入目标库的一张表中,就涉及到多表的同步。多表同步可以有以下两种方式实现,接下来笔者就给大家分别介绍下实现方式:方式一:多表关联查询后,写入一张表1、根据这两张表的数据,表有学生表和班级表,写入目标表:学生班级表2、选择表输入,双击表输入,在sql一栏里写入关联...

weixin_39708708的博客 628

Mybatis plus 多表分页查询实践和注意点

单表的Mybatis plus 平时单表Mybatis plus 挺简单的。最近遇到两个表的连接查询。想到用mybatis plus 不合适。项目又没有用pageHelper ,自己写SQL又要 自己写分页。 就琢磨下 mybatis plus 如何多表连接查询 @TableField 注解 官网描述 这个注解可以加在字段上 。 第一个解决是想要将查询的数据列 (放到当前对象里。)如何处理连接字段? xml 中描述 第二个问题 如何用到它的分页,不用管 生效了。 第三个问题,开干 DO 属性 加入不是当前表

huang__2的博客 982
上一篇: MyBatisPlus主键生成策略
下一篇: Qt 连接并使用 SQL Sever数据库
AIGC镜像空间
博客等级 码龄5年 4万+粉丝 689原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值