IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> MyBatis-Plus 多表查询 -> 正文阅读

[JavaScript知识库]MyBatis-Plus 多表查询

MP提供了大量单表查询的方法,但是没有多表的操作,所以涉及到多表的查询时,需要我们自己实现

思路1

因为MP是基于MyBatis实现,我们可以使用MyBatis的结果映射来做,下面是一个官网的例子

https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps

结果映射

<!-- 非常复杂的语句 -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       A.id as author_id,
       A.username as author_username,
       A.password as author_password,
       A.email as author_email,
       A.bio as author_bio,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>

这个对象表示了一篇博客,它由某位作者所写,有很多的博文,每篇博文有零或多条的评论和标签。 我们先来看看下面这个完整的例子,它是一个非常复杂的结果映射(假设作者,博客,博文,评论和标签都是类型别名)

<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>

resultMap 元素有很多子元素和一个值得深入探讨的结构。 下面是resultMap 元素的概念视图。

在这里插入图片描述

查询的结果,会通过上面的结果映射,映射为下面这个类的实例

Blog.java

/**
 * 博客
 */
@Data
public class Blog {
    private int id;

    private String title;

    private Author author;

    private List<Post> posts;
}

/**
 * 博文
 */
@Data
class Post{
    private int id;

    private String subject;

    private Author author;

    private List<Comment> comments;

    private List<Tag> tags;
}

/**
 * 作者
 */
@Data
class Author{
    private int id;

    private String username;

    private String password;

    private String email;

    private String bio;

    private String favourite_section;
}

/**
 * 评论
 */
@Data
class Comment{
    private int id;
}

/**
 * 标签
 */
@Data
class Tag{
    private int id;
}

多表关联查询

数据库准备:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多表关联查询常用的有:
● 内联查询
● 左联查询
● 右联查询
● 全联查询

内联查询

inner join 为默认连接,join如果不带有其他标识,则默认是内联,即join=inner join

SELECT *
FROM pri_class p INNER JOIN student s
ON p.class_id = s.student_id;

在这里插入图片描述
内联查询数据集的来源
第一步 左表的记录和右表的记录逐一匹配
第二步 左表没有匹配到右表的记录,这一行废弃;
第三步 右表没有匹配到左表的记录,这一行废弃;

这里的左表、右边的叫法指的是inner join的左边和右边

左联查询

在这里插入图片描述

左联查询的数据集来源分析
第一步 左表的记录和右表的记录逐一匹配;
第二步 左表的数据全部保留
第三步 右表的数据如果匹配到左表、那么保留右表的数据;
第四步 右表的数据如果没有匹配到左表、那么保留左表数据,右表记录为空;

左联查询和内联查询的区别
左联查询的结果比内联多出了一部分,多出的部分是没有匹配到右表的左表记录。

右联查询

在这里插入图片描述
右联查询的数据集来源分析
第一步 右表的记录和左表的记录逐一匹配;
第二步 右表的数据全部保留
第三步 左表的数据如果匹配到右表、那么保留左表的数据;
第四步 左表的数据如果没有匹配到右表、那么保留右表数据,左表记录为空;

右联查询和内联查询的区别
右联查询的结果比内联多出了一部分,多出的部分是没有匹配到左表的右表记录。

全联查询

将来左联和右联的结果做一次UNION,求并集再去重;

示例

工程目录,基于MP自动生成的代码

CodeGenerator.java

public class CodeGenerator {
    public static void main(String[] args) {
        //配置 GlobalConfig
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        globalConfig.setAuthor("blazar");
        globalConfig.setOpen(false);
        //设置主键策略
        globalConfig.setIdType(IdType.ASSIGN_ID);
        globalConfig.setFileOverride(true);
        globalConfig.setActiveRecord(true);
        globalConfig.setEnableCache(false);

        //配置 DataSourceConfig
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://xx.xx.xx.xx:3306/primary_school?useSSL=true&useUnicode=true&characterEncoding=UTF-8");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("123456");

        //包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.example.primarySchool")
                .setMapper("mapper");

        //策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setCapitalMode(true).setNaming(NamingStrategy.underline_to_camel);

        //配置代码生成器
        AutoGenerator mpg = new AutoGenerator();
        mpg.setGlobalConfig(globalConfig);
        mpg.setDataSource(dataSourceConfig);
        mpg.setPackageInfo(packageConfig);
        mpg.setStrategy(strategyConfig);

        //指定自定义模板路径, 位置:/resources/templates/entity2.java.ftl(或者是.vm)
        //注意不要带上.ftl(或者是.vm), 会根据使用的模板引擎自动识别
        TemplateConfig templateConfig = new TemplateConfig();
        //配置自定义模板
        mpg.setTemplate(templateConfig);

        //执行
        mpg.execute();
    }
}

然后手动添加红色框中的类

在这里插入图片描述

ClassDetail.java

@Data
public class ClassDetail {
    /**
     * 班级id
     */
    @TableId(value = "class_id", type = IdType.ASSIGN_ID)
    private Long classId;

    /**
     * 班级名称
     */
    private String nickname;

    /**
     * 学生信息
     */
    private List<Student> students;
}

然后,依次完成下列步骤:

在PriClassMapper中添加方法

public interface PriClassMapper extends BaseMapper<PriClass> {
    ClassDetail getDetailById(Serializable id);
}

然后在XML文件中写SQL和映射

<?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.primarySchool.mapper.PriClassMapper">

    <select id="getDetailById" resultMap="detailedClassResultMap">
        SELECT
            p.class_id AS class_id,
            p.nickname AS cname,
            s.student_id AS student_id,
            s.nickname AS sname
        FROM pri_class p JOIN student s
        ON p.class_id = s.class_id
        WHERE p.class_id = #{id}
    </select>

    <resultMap id="detailedClassResultMap" type="com.example.primarySchool.entity.ClassDetail">
        <result property="classId" column="class_id"/>
        <result property="nickname" column="cname"/>
        <collection property="students" ofType="com.example.primarySchool.entity.Student">
            <id property="studentId" column="student_id"/>
            <result property="nickname" column="sname"/>
            <result property="classId" column="class_id"/>
        </collection>
    </resultMap>
</mapper>

再在service层中调用mapper中自定义的方法,通过getBaseMapper()来获取mapper的实例

public interface IPriClassService extends IService<PriClass> {
    ClassDetail getDetailById(Serializable id);
}
@Service
public class PriClassServiceImpl extends ServiceImpl<PriClassMapper, PriClass> implements IPriClassService {
    @Override
    public ClassDetail getDetailById(Serializable id) {
        return getBaseMapper().getDetailById(id);
    }
}

最后,在Controller层中,写WebAPI接口

@RestController
@RequestMapping("/priClass")
public class PriClassController {
    @Autowired
    IPriClassService iPriClassService;

    @RequestMapping("/getDetailById/{id}")
    public String getDetailById(@PathVariable("id") Long id){
        return JSON.toJSONString(iPriClassService.getDetailById(id));
    }
}

测试

在这里插入图片描述

注意:需要在配置文件中配置一下xml的路径,否则会报错Invalid bound statement (not found)

在这里插入图片描述

还可以单独做mapper、service、controller,这样就和用MyBatis一样;

在这里插入图片描述

public interface ClassDetailMapper {
    ClassDetail getDetailById(Serializable id);
}
public interface IClassDetailService {
    ClassDetail getDetailById(Serializable id);
}
@Service
public class ClassDetailServiceImpl implements IClassDetailService {
    @Autowired
    ClassDetailMapper classDetailMapper;

    @Override
    public ClassDetail getDetailById(Serializable id) {
        return classDetailMapper.getDetailById(id);
    }
}

然后在Controller调用Service的方法就可以了;

思路2

使用单表查询的结果拼接成多表查询的结果,示例如下

在这里插入图片描述

@RestController
@RequestMapping("/priClass")
public class PriClassController {
    @Autowired
    IPriClassService iPriClassService;

    @Autowired
    IStudentService iStudentService;

    @Autowired
    ClassAllInfo classAllInfo;

    @RequestMapping("/getAllById/{id}")
    public String getAllById(@PathVariable("id") Long id){
        PriClass priClass = iPriClassService.getById(id);
        classAllInfo.setClassId(priClass.getClassId());
        classAllInfo.setNickname(priClass.getNickname());

		//条件查询
        Map<String, Object> map = new HashMap<>();
        map.put("class_id", id);
        List<Student> studentList = iStudentService.listByMap(map);
        classAllInfo.setStudentList(studentList);

        return JSON.toJSONString(classAllInfo);
    }
}

数据库如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这种做法只需要新添加一个ClassAllInfo类,其他的拼接逻辑在controller层或者service层完成都可以:

@Data
@Component
public class ClassAllInfo {
    /**
     * 班级id
     */
    @TableId(value = "class_id", type = IdType.ASSIGN_ID)
    private Long classId;

    /**
     * 班级名称
     */
    private String nickname;

    private List<Student> studentList;
}

这种做法的好处是可以利用到MP自动生成的各种单表操作,不用手动写各种SQL,但是缺点就是不够灵活,如果查询的条件更加复杂的话,采用Wrapper的方式来描述查询条件可能也没有SQL直观;另一方面,把本来属于一次查询的任务,分成了多次来做,也不利于查询优化;

PriClass.java

@Data
public class PriClass extends Model<PriClass> {

    /**
     * 班级id
     */
    @TableId(value = "class_id", type = IdType.ASSIGN_ID)
    private Long classId;

    /**
     * 班级名称
     */
    private String nickname;

}

Student.java

@Data
public class Student extends Model<Student> {
    /**
     * 学生id
     */
    @TableId(value = "student_id", type = IdType.ASSIGN_ID)
    private Long studentId;

    /**
     * 学生姓名
     */
    private String nickname;

    /**
     * 班级id
     */
    private Long classId;
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 15:53:03  更:2021-12-18 15:53:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:56:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码