Mybatis后端数据库查询多对多查询解决方案

问题场景:

我开发的是一个论文选择系统。

后端用一个论文表paper来存储论文信息。

论文信息中,包含前置课程,也就是你需要修过这些课程才能选择这个论文。

而一个论文对应的课程有很多个。

这样就造成了一个数据库存储的问题。一个paper里面要存储多个course。如何解决这个问题。

方案一:

在创建paper表,存储course,可以将course存储为一个字符串,用指定的分隔符分割。在取出数据的时候。在service层将字符串再重新解析成数组的形式。

这种方案好处是在数据库层面非常方便,但是在service层非常麻烦。

如果需要对paper和course进行修改和删除也将非常的麻烦。需要一遍一遍的解析字符串,修改,重新生成字符串。

而且还有一个重要的问题。如果面对团队合作,这种方法十分受限,因为别人不知道,甚至有一天自己都忘了自己设置的分割符是什么了。

所以这种方法不太可取。

方案二:

我们创建一个中间表。记录这paperId和courseId的对应。

这样你的paper里面就不需要有course等这种字段了。

这种方式的好处就是容易维护,也比较容易理解。

代码实操:

增加

增加paper的时候,只需要获取到paperId和courses数组中的courseId然后调用paper_course中间表的添加操作即可。

这里默认大家熟悉对数据库基础的增删改查。

但是有一个问题。

当在service层插入paper的时候,paperId还没生成。

其实这个无需担心,你只需要先插入paper,然后你在paper里就可以拿到了。

service层

java 复制代码
    public void add(Paper paper) {
        paperMapper.add(paper);
        addMiddleData(paper);
    }

    private void addMiddleData (Paper paper) {
        Integer paperId = paper.getId();
        List<Integer> courseIds = paper.getCourseIds();
        List<Integer> languageIds = paper.getLanguageIds();
        List<Integer> technologyIds = paper.getTechnologyIds();
        if (courseIds != null && !courseIds.isEmpty()) {
            for (Integer courseId : courseIds) {
                paperCourseMapper.add(new PaperCourse(paperId, courseId));
            }
        }
        if(languageIds != null && !languageIds.isEmpty()) {
            for (Integer languageId : languageIds) {
                paperLanguageMapper.add(new PaperLanguage(paperId, languageId));
            }
        }
        if (technologyIds != null && !technologyIds.isEmpty()) {
            for (Integer technologyId : technologyIds) {
                paperTechnologyMapper.add(new PaperTechnology(paperId, technologyId));
            }
        }
    }

paperMapper

XML 复制代码
<mapper namespace="com.paper.mapper.PaperMapper">
    <insert id="add" parameterType="com.paper.entity.Paper" useGeneratedKeys="true" keyProperty="id">
        insert into `paper`
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">id,</if>
            <if test="teacherId != null">teacher_id,</if>
            <if test="studentId != null">student_id,</if>
            <if test="name != null">name,</if>
            <if test="resource != null">resource,</if>
            <if test="content != null">content,</if>
            <if test="studentGroup != null">student_group,</if>
            <if test="type != null">type,</if>
            <if test="gpa != null">gpa,</if>
            <if test="requirement != null">requirement,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">#{id},</if>
            <if test="teacherId != null">#{teacherId},</if>
            <if test="studentId != null">#{studentId},</if>
            <if test="name != null">#{name},</if>
            <if test="resource != null">#{resource},</if>
            <if test="content != null">#{content},</if>
            <if test="studentGroup != null">#{studentGroup},</if>
            <if test="type != null">#{type},</if>
            <if test="gpa != null">#{gpa},</if>
            <if test="requirement != null">#{requirement},</if>
        </trim>
    </insert>
    <delete id="delete">

查询

要查询paper表,需要连接表。

我这里想着重说一下连接表的一个小技巧。

如果只有一个中间表的话,直接用join可能会好一些。然后直接把想查的元素全都查出来就好了。

但是我的场景是,我有三个中间表。

我需要一直join。

并且我要以数组的形式查出来。直接查无法实现这样。

我在course表中,定义一个查询

XML 复制代码
    <select id="selectCourseByPaperId" resultType="com.paper.entity.Course">
        select c.*, pc.paper_id from course c
        left join `paper-sys`.paper_course pc on c.id = pc.course_id
        where paper_id = #{paperId}
    </select>

这个查询是查询course表中对应paperId的所有course

在paperMapper.xml中定义一个resultType

XML 复制代码
    <resultMap id="PaperResultMap" type="com.paper.entity.Paper">
        <id property="id" column="id" />
        <result property="teacherId" column="teacher_id" />
        <result property="studentId" column="student_id" />
        <result property="name" column="name" />
        <result property="resource" column="resource" />
        <result property="content" column="content" />
        <result property="studentGroup" column="student_group" />
        <result property="type" column="type" />
        <result property="gpa" column="gpa" />
        <result property="requirement" column="requirement" />
        <collection property="courses" ofType="com.paper.entity.Course"
                    select="com.paper.mapper.CourseMapper.selectCourseByPaperId"
                    column="id">
        </collection>
        <collection property="languages" ofType="com.paper.entity.Language"
                    select="com.paper.mapper.LanguageMapper.selectLanguageByPaperId"
                    column="id">
        </collection>
        <collection property="technologies" ofType="com.paper.entity.Technology"
                    select="com.paper.mapper.TechnologyMapper.selectTechnologyByPaperId"
                    column="id">
        </collection>
    </resultMap>

我这里是关联了三个表。

一个表理解了,三个表一样的。

这个定义了我要的resultType,因为刚刚说了,我要保证我能接受到结果数组。

所以数组部分用collection来接收。

而这个collection连接这刚刚对应的select

也就是这个数组已经被查出来了。

XML 复制代码
    <select id="selectByPage" resultMap="PaperResultMap">
        select * from `paper`
       <where>
            <if test="teacherId != null">and teacher_id = #{teacherId}</if>
            <if test="studentId != null">and student_id = #{studentId}</if>
        </where>
    </select>

最后使用resultMap来定义接受的格式。

那么我们就完成了查询。

是不是非常的优雅呢?

这虽然比join一堆麻烦,但是当代码跑通的那一刻,一切都值得。

相关推荐
ZhengEnCi13 分钟前
🚀创建第一个 SpringBoot 应用-零基础体验开箱即用的神奇魅力
java·spring boot
非凡的世界14 分钟前
微服务——SpringBoot使用归纳——Spring Boot中使用拦截器——拦截器的快速使用
spring boot·微服务·架构
骷髅头的寂寞37 分钟前
Spring Boot 整合 Thymeleaf 生成 HTML 页面教学
spring boot·html·intellij-idea
忧郁的蛋~1 小时前
EFcore查询a表中符合b表列的值
数据库
xwz小王子1 小时前
ManipulationNet:开启真实世界机器人操作基准测试新时代
数据库·机器人
咯哦哦哦哦1 小时前
关于QT 打印中文 乱码问题
java·数据库·qt
野犬寒鸦2 小时前
从零起步学习Redis || 第十二章:Redis Cluster集群如何解决Redis单机模式的性能瓶颈及高可用分布式部署方案详解
java·数据库·redis·后端·缓存
ShooterJ2 小时前
Mysql小表驱动大表优化原理
数据库·后端·面试
程序员三明治2 小时前
【MyBatis从入门到入土】告别JDBC原始时代:零基础MyBatis极速上手指南
数据库·mysql·mybatis·jdbc·数据持久化·数据
cookqq2 小时前
MongoDB源码delete分析oplog:从删除链路到核心函数实现
数据结构·数据库·sql·mongodb·nosql