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一堆麻烦,但是当代码跑通的那一刻,一切都值得。

相关推荐
冒泡的肥皂2 小时前
MVCC初学demo(一
数据库·后端·mysql
.Shu.3 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
薛晓刚6 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队6 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光6 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12016 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
白仑色6 小时前
Spring Boot 全局异常处理
java·spring boot·后端·全局异常处理·统一返回格式
染落林间色6 小时前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
数据库·sql
Monly217 小时前
RabbitMQ:SpringAMQP 入门案例
spring boot·rabbitmq·java-rabbitmq
Monly217 小时前
RabbitMQ:SpringAMQP Fanout Exchange(扇型交换机)
spring boot·rabbitmq·java-rabbitmq