【MyBatis(-Plus)】一对一、一对多查询

一、前言

工作中常常会碰到联表查询,最近刚刚参加工作,在写查询时发现自己很不熟练,特此总结一下一对一和一对多的查询。

学习时使用的是MyBatis,参加工作了开始学习使用MyBatis-Plus。关于这两者的使用后续会进行总结,在前辈那里得来的结论是:

MyBatis-Plus ⊇ MyBatis

当然需要自己进行操作使用后再来回头总结。本篇使用的是MyBatis-Plus。

在Dao层写sql语句时,我们常用的标签诸如select、update、delete、insert、where、if等等,都需要非常熟悉,我认为这也是代码的基本功吧,关于一对一和一对多,这里使用到的关键标签就是associationcollection

二、准备工作

依赖:

<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.5.2version>
dependency>

application配置文件:

server:
  port: 9999
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/class
    username: root
    password: 123

mybatis-plus:
  mapper-locations: classpath*:/mappers/*Mapper.xml

数据库:

三张表:班级、老师、学生,数据若干。这里没有使用外键,在工作中其实不常使用外键,外键使用过多会造成数据库维护成本过高!

-- ----------------------------
-- Table structure for class
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '班级',
  `head_teacher_id` int(11) DEFAULT NULL COMMENT '班主任',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of class
-- ----------------------------
INSERT INTO `class` VALUES ('1', '1');
INSERT INTO `class` VALUES ('2', '2');
INSERT INTO `class` VALUES ('3', '3');

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学生id',
  `name` varchar(255) DEFAULT NULL COMMENT '学生姓名',
  `class_id` int(11) DEFAULT NULL COMMENT '班级id',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '张三', '1');
INSERT INTO `student` VALUES ('2', '李四', '2');
INSERT INTO `student` VALUES ('3', '王雯雯', '1');
INSERT INTO `student` VALUES ('4', '刘文涛', '3');
INSERT INTO `student` VALUES ('5', '卢毅', '1');
INSERT INTO `student` VALUES ('6', '李晓楠', '2');
INSERT INTO `student` VALUES ('7', '陈果', '2');
INSERT INTO `student` VALUES ('8', '唐浩', '3');
INSERT INTO `student` VALUES ('9', '秦琴', '3');
INSERT INTO `student` VALUES ('10', '王梦娟', '1');

-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '老师id',
  `name` varchar(255) DEFAULT NULL COMMENT '老师名字',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('1', '张江');
INSERT INTO `teacher` VALUES ('2', '王闻彦');
INSERT INTO `teacher` VALUES ('3', '周倩');
INSERT INTO `teacher` VALUES ('4', '李强');

实体类:

班级

@Data
public class Classes {
    private Integer id;
    private Integer headTeacherId;
    private Teacher headTeacher;
    private List<Student> students;
}

老师

@Data
public class Teacher {
    private Integer id;
    private String name;
}

学生

@Data
public class Student {
    private Integer id;
    private String name;
    private Integer classId;
}

​ 这里要说明一下,工作中,班级类的老师和学生这两个属性是不该这样写的,实体类是和数据库中的字段一一对应的,实际工作会按照需求自行创建DTO或者VO类,这里为了省事就这就样直接写了。

三、一对一查询

目标:查出班级的同时要把老师的信息查出来

法一:嵌套 Select 查询

<resultMap id="classResultMap" type="com.example.mybatisplus.entity.Classes">
    <id column="id" property="id"/>
    <result column="head_teacher_id" property="headTeacherId"/>
    <association property="headTeacher" 
                 column="head_teacher_id" 
                 javaType="com.example.mybatisplus.entity.Teacher"
                 select="queryTeacherById"/>
resultMap>
<select id="queryById" resultMap="classResultMap">
    SELECT * FROM classes WHERE id = #{id}
select>
<select id="queryTeacherById" resultType="com.example.mybatisplus.entity.Teacher">
    SELECT * FROM teacher WHERE id = #{id}
select>

说明:

  1. 需要将查询结果结果进行映射到实体类
  2. property属性表示一对一中被包含的对象,例如例子中的:班级中的老师对象
  3. column属性表示数据库的“外键”,例如班主任老师id
  4. javaType属性表示子查询的结果所映射的全限定类名(非必填,MyBatis会自动检测找到相应的类,但是还是建议填上)
  5. select表示子查询语句的id,例如:这里表示调用id为queryTeacherById的查询语句,其中column作为参数传入

法二:嵌套结果映射

<resultMap id="classResultMap" type="com.example.mybatisplus.entity.Classes">
    <id column="id" property="id"/>
    <result column="head_teacher_id" property="headTeacherId"/>
    <association property="headTeacher" javaType="com.example.mybatisplus.entity.Teacher">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
    association>
resultMap>
<select id="queryById" resultMap="classResultMap">
    SELECT * FROM classes c LEFT JOIN teacher t ON c.head_teacher_id = t.id WHERE c.id = #{id}
select>

说明:

  1. 在结果映射中将结果一一映射,在sql语句中使用联表查询
  2. association中的column属性就可以省略不写了
  3. property要和column对应,如果column取了别名要写别名

结果展示:

【MyBatis(-Plus)】一对一、一对多查询_第1张图片

四、一对多查询

目标:查出班级的同时要把所有学生的信息查出来

法一:嵌套 Select 查询

<resultMap id="classResultMap" type="com.example.mybatisplus.entity.Classes">
    <id column="id" property="id"/>
    <result column="head_teacher_id" property="headTeacherId"/>

    <association property="headTeacher" column="id"
                 javaType="com.example.mybatisplus.entity.Teacher"
                 select="queryTeacherById"/>

    <collection property="students"
                column="id"
                ofType="com.example.mybatisplus.entity.Student"
                select="queryStudentByClassId"/>
resultMap>
<select id="queryStudentByClassId" resultType="com.example.mybatisplus.entity.Student">
    SELECT * FROM student WHERE class_id = #{id}
select>
<select id="queryById" resultMap="classResultMap">
    SELECT * FROM classes c LEFT JOIN teacher t ON c.head_teacher_id = t.id WHERE c.id = #{id}
select>
<select id="queryTeacherById" resultType="com.example.mybatisplus.entity.Teacher">
    SELECT * FROM teacher WHERE id = #{id}
select>

说明:

  1. 与一对一的查询几乎一样
  2. 映射的结果是一个集合,javaType则为集合的类型,这里是list
  3. ofType是集合中的对象类型,这里是学生

法二:嵌套结果映射

<resultMap id="classResultMap" type="com.example.mybatisplus.entity.Classes">
    <id column="id" property="id"/>
    <result column="head_teacher_id" property="headTeacherId"/>

    <association property="headTeacher" javaType="com.example.mybatisplus.entity.Teacher">
        <id column="t_id" property="id"/>
        <result column="t_name" property="name"/>
    association>

    <collection property="students" javaType="list" ofType="com.example.mybatisplus.entity.Student">
        <id column="s_id" property="id"/>
        <result column="s_name" property="name"/>
        <result column="s_class_id" property="classId"/>
    collection>
resultMap>
<select id="queryById" resultMap="classResultMap">
    SELECT c.*, t.id t_id, t.name t_name, s.id s_id, s.name s_name, s.class_id s_class_id FROM classes c
    LEFT JOIN teacher t ON c.head_teacher_id = t.id
    LEFT JOIN student s ON s.class_id = c.id
    WHERE c.id = #{id}
select>

说明:

  1. 注意这里要给查出来的字段取别名
  2. 映射结果和查出的别名要一一对应

结果展示:

【MyBatis(-Plus)】一对一、一对多查询_第2张图片

五、总结

关于MyBatis和MyBatis-Plus的使用本人并不是很熟悉,以上写法只是我在工作中容易碰到的,所以进行一个总结,怕自己容易忘。

本人今年刚毕业,第一次写博客,若有错漏之处或者更优雅写法请评论区友好指出,谢谢!

你可能感兴趣的:(mybatis,mysql,java)