【SSM】Mybatis系列——多对一和一对多的处理、动态SQL

167 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第十八天,点击查看活动详情 >>

10 多对一处理

在这里插入图片描述

多个学生,对应老师

对于这边而言,关联 多个学生,关联一个老师【多对一】

对于老师而言,集合 一个老师,有很多学生 【一对多】

CREATE TABLE `teacher`(
 `id` INT(10) NOT NULL,
 `name` VARCHAR (30) DEFAULT NULL,
 PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES(1,'秦老师');

CREATE TABLE `student`(
 `id` INT(10) NOT NULL,
 `name` VARCHAR(30) DEFAULT NULL,
 `tid` INT(10) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `fktid` (`tid`),
 CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student` (`id`, `name`, `tid`) VALUES('2', '小亮', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES('3', '小黑', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES('4', '小白', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES('5', '小雨', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES('6', '小哥', '1'); 

10.1 测试环境搭建

  • 导入lombok
  • 新建实体类 Teacher、Student
  • 建立Mapper 接口
  • 建立Mapper.xml文件
  • 在核心配置文件中绑定注册我们的Mapper接口或者文件!!【方式很多 随意挑选】
  • 测试查询成功与否

10.2 按照查询嵌套处理(子查询)

<!--
     思路:
        1. 查询所有的学生信息
        2. 根据查询出来的学生的tid寻找特定的老师 (子查询)
-->
<select id="getStudent" resultMap="StudentTeacher">
    select * from student
</select>
<resultMap id="StudentTeacher" type="student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性,我们需要单独出来 对象:association 集合:collection-->
    <collection property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
    select * from teacher where id = #{id}
</select>

10.3 按照结果嵌套 处理(联表查询 )

<!--按照结果进行查询-->
<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid , s.name sname, t.name tname
    from student s,teacher t
    where s.tid=t.id
</select>

<!--结果封装,将查询出来的列封装到对象属性中-->
<resultMap id="StudentTeacher2" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="name" column="tname"></result>
    </association>
</resultMap>

10.4 Mysql多对一查询方式:

  • 子查询 (按照查询嵌套)
  • 联表查询 (按照结果嵌套)

11 一对多处理

比如:一个老师有多个学生!

对于老师而言,就是一对多的关系!

1、环境搭建

环境搭建,和刚才一样 实体类

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data
public class Teacher {
    private int id;
    private String name;
//一个老师拥有多个学生
private List<Student> student;
}

2、按照结果嵌套查询

<!--按照结果嵌套处理-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid, s.name sname, t.name tname, t.id tid
        from student s, teacher t
        where s.tid = t.id and t.id=#{tid}
    </select>
<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>

    <!--复杂的属性,我们需要单独出来 对象:association 集合:collection

    指定的属性类型使用 javaType=""
    集合中的泛型信息使用 ofTYpe=" " 获取
    -->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

3、按照查询嵌套处理

<!--(子查询)-->   
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id=#{tid};
    </select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudent" column="id"/>
</resultMap>

<select id="getStudent" resultType="Student">
    select * from mybatis.student where tid=#{tid};
</select>

小结

  • 关联 - association 【多对一】
  • 集合 - collection 【对多】
  • JavaType & ofType
    • JavaType 用来指定实体类中属性的类型
    • ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

  • 尽量保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多、多对一中,属性名和字段问题!!
  • 如果问题不好排除,可以使用日志~ 建议Log4j 【其实默认的也够用了】
  • 避免慢SQL

面试:

  • Mysql 引擎
  • InnoDB底层原理
  • 引擎
  • 索引优化!

@[toc]

12 动态SQL

什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句

利用动态SQL这一特性可以摆脱这种痛苦。

动态SQL元素和JSTL或基于类似XML的文本处理器相似。在Mybatis之前的版本中,有很多元素需要花时间了解。Mybatis 3大大精简了元素种类,现在只需要学习原来的一半的元素便可以了。Mybatis采用功能强大的基于OGNL的表达式来淘汰其他大部分元素

  • if
  • choose (when,otherwise)
  • trim (where, set)
  • foreach

12.1 搭建环境

CREATE TABLE `blog`(
	`id` VARCHAR(50) NOT NULL COMMENT '博客',
	`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
	`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	`views` INT(30) NOT NULL COMMENT'浏览器'
)ENGINE=INNODB DEFAULT CHARSET=utf8
  • 创建一个基础工程
  • 导包
  • 编写配置文件
  • 编写实体类
  • 编写实体类对应的Mapper接口和Mapper.xml文件

12.2 IF

<!--parameterType 输入类型
        resultType    返回结果集
    -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from mybatis.blog where 1=1
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</select>

12.3 choose (when,otherwise)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views=#{views}
            </otherwise>
        </choose>
    </where>
</select>

12.4 trim (where, set)

<!-- where标签  会去除多余的 “AND” 或 “OR”,或 "where" -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>
<!-- set标签  会去除多余的 " 逗号",或 "set" -->
<update id="updateBlog" parameterType="map" >
    update mybatis.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    where id = #{id}
</update>

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

if where set choose when

12.5 SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便复用

使用SQL标签抽取公共部分

<sql id="sql-if-title-author">
    <if test="title != null">
        title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>

在需要使用的地方使用Include标签引用即可

<!--parameterType 输入类型
        resultType    返回结果集
    -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <include refid="sql-if-title-author"/>
    </where>
</select>

注意事项:

最好基于单表定义SQL片段!! sql标签不要存在where标签 因为他是动态的

12.6 Foreach

select * from user where 1=1 and 

<foreach item="id" collection="ids" open="(" separator="or" close=")">
	#{id}
</foreach>

(id=1 or id=2 or id=3)

在这里插入图片描述

相当于遍历一个数组

<!--
        集合 select * from user where 1=1 and (id=1 or id=2 or id=3)    
    我们现在传递一个万能的map,这map可以存在一个集合!
    collection:集合      item:集合里的数据
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <foreach item="id" collection="ids" open="and (" separator="or" close=")">
            id=#{id}
        </foreach>
    </where>
</select>

动态SQL就是拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:

现在Mybatis中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可