Mybatis的多表查询操作 1

简介: Mybatis的多表查询操作

1 mybatis多表查询XML方式

1.1 一对一查询

1.1.1 表关系

一对一关系中,表关系由任意一方维护,以人和身份证为例,一个人对应一个身份证,一个身份证对应一个人。本案例中由身份证表维护表关系

1.1.2 需求

查询所有的身份证,并且要将身份证对应的人也查询出来

1.1.3 实现步骤

第一步:建表

DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL COMMENT '姓名',
  `age` int(11) NOT NULL COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用户表';
insert  into `person`(`id`,`name`,`age`) values (1,'陈乔恩',39),(2,'钟汉良',44),(3,'林志颖',44),(4,'吴奇隆',48);
DROP TABLE IF EXISTS `card`;
CREATE TABLE `card` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `number` varchar(30) NOT NULL COMMENT '身份证号',
  `pid` int(11) NOT NULL COMMENT '所属用户',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='身份证表';
insert  into `card`(`id`,`number`,`pid`) values (1,'  110101199003079008',1),(2,'110101199003079331',2),(3,'  11010119900307299X',3),(4,' 110101199003070791',4);

第二步:创建实体类

Person 人类

package cn.oldlu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private Integer id;
    private String name;
    private Integer age;
}

Card 身份证类,因为需求是查询身份证,并且查询对应的人,所以应该是Card实体类中存放Perosn属性

package cn.oldlu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Card {
    private Integer id;
    private String number;
    private Person person;
}

第三步:创建Dao接口

package cn.oldlu.dao;
import cn.oldlu.domain.Card;
import java.util.List;
public interface CardDao {
    List<Card> findAll();
}

第四步:创建映射文件

resultMap的分析与编写

在src或resources目录创建CardMapper.xml

<?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">
<!--namespace的值是UserDao的类全名-->
<mapper namespace="cn.oldlu.dao.CardDao">
    <resultMap id="cardMap" type="card">
        <!--把结果集中cid这一列赋值给id属性-->
        <id column="cid" property="id"></id>
        <!--把结果集中cnumber这一列的值赋值给number属性-->
        <result column="cnumber" property="number"></result>
        <!--给person属性赋值-->
        <association property="person" javaType="person">
            <!--把结果集中的pid这一列的值赋值给id属性-->
            <id column="pid" property="id"></id>
            <!--把结果集中的pname这一列的值赋值给name属性-->
            <result column="pname" property="name"></result>
            <!--把结果集中的page这一列的值赋值给age属性-->
            <result column="page" property="age"></result>
        </association>
    </resultMap>
    <select id="findAll" resultMap="cardMap">
        SELECT
            c.id 'cid',
            c.number 'cnumber',
            p.id 'pid',
            p.name 'pname',
            p.age 'page'
        FROM card c
        LEFT JOIN person p ON p.id = c.pid
    </select>
</mapper>

第五步:主配置导入映射文件

在mybatis-config.xml中的mappers标签中引入CardMapper.xml

<mappers>
    <mapper resource="CardMapper.xml"></mapper>
</mappers>

第六步:编写测试方法

@Test
public void testFindAll()throws Exception{
    /*1.读取配置文件并创建SqlSessionFactory*/
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    /*2.获取sqlSession[这是mybatis的重要API, 使用它可以操作数据库crud*/
    SqlSession sqlSession = sqlSessionFactory.openSession();
    /*3.由Mybatis框架创建CardDao的实现类对象,我们称为代理对象*/
    CardDao cardDao = sqlSession.getMapper(CardDao.class);
    /*4.查询所有身份证*/
    List<Card> cards = cardDao.findAll();
    /*5.释放资源*/
    sqlSession.close();
    //测试查询结果
    System.out.println(cards);
}

1.1.4 小结

一对一查询,使用resultMap+association标签

1.2 一对多查询

1.2.1 表关系

一对多关系中,表关系由多的一方维护,以班级和学生为例,一个班级可以有多个学生,学生表应该维护表关系。

1.2.2 需求

查询所有班级信息,并且要将班级对应的学生信息也同时查询出来

1.2.3 实现步骤

第一步:建表

DROP TABLE IF EXISTS `classes`;
CREATE TABLE `classes` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(20) DEFAULT NULL COMMENT '班级名称',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='班级表';
INSERT  INTO `classes`(`id`,`name`) VALUES (1,'一班'),(2,'二班');
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(24) NOT NULL,
  `age` INT(11) NOT NULL,
  `cid` INT(11) NOT NULL COMMENT '所属班级',
  PRIMARY KEY (`id`),
  KEY `cid` (`cid`)
) ENGINE=INNODB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
INSERT  INTO `student`(`id`,`name`,`age`,`cid`) VALUES (8,'王力宏',23,1),(9,'张韶涵',22,1),(10,'张晋',24,1),(11,'罗晋',25,1),(12,'唐僧',12,2),(13,'孙悟空',22,2),(14,'猪八戒',21,2);

第二步:创建实体类

Student学生类

package cn.oldlu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Integer age;
}

Classes班级类,因为需求是查询班级,以及对应的学生,所以应该是班级类中定义List表示一堆学生

package cn.oldlu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Classes {
    private Integer id;
    private String name;
    private List<Student> students;
}

第三步:创建Dao接口

package cn.oldlu.dao;
import cn.oldlu.domain.Classes;
import java.util.List;
public interface ClassesDao {
    List<Classes> findAll();
}

第四步:创建映射文件

resultMap的分析与编写

在src或者resources目录下创建ClassesMapper.xml

<?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="cn.oldlu.dao.ClassesDao">
    <resultMap id="classesMap" type="classes">
        <id column="cid" property="id"></id>
        <result column="cname" property="name"></result>
        <collection property="students" ofType="student">
            <id column="sid" property="id"></id>
            <result column="sname" property="name"></result>
            <result column="sage" property="age"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="classesMap">
        SELECT
            c.id 'cid',
            c.name 'cname',
            s.id 'sid',
            s.name 'sname',
            s.age 'sage'
        FROM classes c
        LEFT JOIN student s ON s.`cid` = c.`id`
    </select>
</mapper>

第五步:主配置导入映射文件

在mybatis-config.xml中的mappers标签中引入ClassesMapper.xml

<mappers>
    <mapper resource="ClassesMapper.xml"></mapper>
</mappers>

第六步:编写测试方法

@Test
public void testFindAll()throws Exception{
    /*1.读取配置文件并创建SqlSessionFactory*/
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    /*2.获取sqlSession[这是mybatis的重要API, 使用它可以操作数据库crud*/
    SqlSession sqlSession = sqlSessionFactory.openSession();
    /*3.由Mybatis框架创建UserDao的实现类对象,我们称为代理对象*/
    ClassesDao classesDao = sqlSession.getMapper(ClassesDao.class);
    /*4.查询所有班级*/
    List<Classes> classes = classesDao.findAll();
    /*5.释放资源*/
    sqlSession.close();
    //测试结果
    System.out.println(classes);
}

1.2.4 小结

一对多查询,使用resultMap+collection标签

总结:javatype和ofType 都是用来指明对象类型, 区别在于使用的场合不一样, javatype是在pojo属性类型, ofType指定是当对象需要Collection进行list集合映射对象的时候使用 ofType,也就是一对多映射的时候使用

1.3 多对多关系

1.3.1 表关系

多对多关系中表关系由中间表维护,以学生和课程为例,一个学生对应多们课程,一个课程同时对应多个学生

1.3.2 需求

查询所有的学生,并且要将学生对应的课程也查询出来

1.3.3 实现步骤

第一步: 建表

DROP TABLE IF EXISTS `classes`;
CREATE TABLE `classes` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(20) DEFAULT NULL COMMENT '班级名称',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='班级表';
INSERT  INTO `classes`(`id`,`name`) VALUES (1,'一班'),(2,'二班');
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(24) NOT NULL,
  `age` INT(11) NOT NULL,
  `cid` INT(11) NOT NULL COMMENT '所属班级',
  PRIMARY KEY (`id`),
  KEY `cid` (`cid`)
) ENGINE=INNODB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
INSERT  INTO `student`(`id`,`name`,`age`,`cid`) VALUES (8,'王力宏',23,1),(9,'张韶涵',22,1),(10,'张晋',24,1),(11,'罗晋',25,1),(12,'唐僧',12,2),(13,'孙悟空',22,2),(14,'猪八戒',21,2);
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(30) NOT NULL COMMENT '课程名',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='课程表';
INSERT  INTO `course`(`id`,`name`) VALUES (1,'语文'),(2,'数学');
DROP TABLE IF EXISTS `stu_cr`;
CREATE TABLE `stu_cr` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `sid` INT(11) NOT NULL,
  `cid` INT(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
INSERT  INTO `stu_cr`(`id`,`sid`,`cid`) VALUES (1,8,1),(2,8,2),(3,9,1),(4,10,2),(5,13,2),(6,13,1),(7,14,1),(8,11,2),(9,12,1),(10,12,2);

第二步:创建实体类

Course 课程类

package cn.oldlu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
    /**课程ID*/
    private Integer id;
    /**课程名*/
    private String name;
}

Student 学生类,学生类之前已经定义过了,只需要添加新的course属性即可。因为需求是查询学生信息,以及对应的课程,所以应该在学生类中定义List,表示一堆课程

package cn.oldlu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private List<Course> courses;
}

第三步:创建Dao接口

package cn.oldlu.dao;
import cn.oldlu.domain.Student;
import java.util.List;
public interface StudentDao {
    List<Student> findAll();
}

第四步:创建映射文件

resultMap的分析与编写

在src或resources目录下创建StudentMapper.xml

<?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">
<!--namespace的值是UserDao的类全名-->
<mapper namespace="cn.oldlu.dao.StudentDao">
    <resultMap id="studentMap" type="student">
        <!--把结果集中sid这一列赋值给id属性-->
        <id column="sid" property="id"></id>
        <!--把结果集中sname这一列的值赋值给name属性-->
        <result column="sname" property="name"></result>
        <!--把结果集中sage这一列的值赋值给age属性-->
        <result column="sage" property="age"></result>
        <!--给courses属性赋值-->
        <collection property="courses" ofType="course">
            <!--把结果集中的cid这一列的值赋值给id属性-->
            <id column="cid" property="id"></id>
            <!--把结果集中的cname这一列的值赋值给name属性-->
            <result column="cname" property="name"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="studentMap">
        SELECT
            s.id 'sid',
            s.name 'sname',
            s.age 'sage',
            c.id 'cid',
            c.name 'cname'
        FROM student s
        LEFT JOIN stu_cr sc ON s.id = sc.`sid`
        LEFT JOIN course c ON c.`id` = sc.`cid`
    </select>
</mapper>

第五步:主配置导入映射文件

在mybatis-config.xml中的mappers标签中引入StudentMapper.xml

<mappers>
    <mapper resource="StudentMapper.xml"></mapper>
</mappers>

第六步:编写测试方法

@Test
public void testFindAll()throws Exception{
    /*1.读取配置文件并创建SqlSessionFactory*/
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    /*2.获取sqlSession[这是mybatis的重要API, 使用它可以操作数据库crud*/
    SqlSession sqlSession = sqlSessionFactory.openSession();
    /*3.由Mybatis框架创建UserDao的实现类对象,我们称为代理对象*/
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    /*4.查询所有学生*/
    List<Student> students = studentDao.findAll();
    /*5.释放资源*/
    sqlSession.close();
    //测试结果
    System.out.println(students);
}

1.3.5 小结

多对多查询,使用resultMap+collection标签

1.4 多表查询总结

什么情况使用resultMap标签

情况1:如果查询的结果集的列名和实体类的属性名不匹配,就需要使用resultMap建立匹配规则

情况2:如果涉及到多表查询也需要使用resultMap标签,一对一查询用resultMap+association,一对多和多对多 resultMap+collection

目录
相关文章
|
5月前
|
XML Java 数据库连接
【MyBatis】MyBatis操作数据库(一)
【MyBatis】MyBatis操作数据库(一)
48 1
|
5月前
|
XML Java 数据库连接
如何使用 MyBatis 来进行增、删、改、查操作
如何使用 MyBatis 来进行增、删、改、查操作
158 2
|
5月前
|
SQL 存储 Java
基于MyBatis的增删改查操作
基于MyBatis的增删改查操作
41 1
|
5月前
|
缓存 Java 数据库连接
我们后端程序员不是操作MyBatis的CRUD Boy
大家好,我是南哥。一个对Java程序员进阶成长颇有研究的人,今天我们接着新的一篇Java进阶指南。为啥都戏称后端是CRUD Boy?难道就因为天天怼着数据库CRUD吗?要我说,是这个岗位的位置要的就是你CRUD,你不得不CRUD。哪有公司天天能给你搭建高并发、高可用、大数据框架的活呢,一条业务线总要成长吧,慢慢成熟了就要装修工来缝缝补补、美化美化,也就是CRUD的活。不能妄自菲薄CRUD Boy,我们是后端工程师。今天来指南下操作数据库之MyBatis框架。
120 3
我们后端程序员不是操作MyBatis的CRUD Boy
|
4月前
|
SQL 缓存 Java
使用MyBatis优化Java持久层操作
使用MyBatis优化Java持久层操作
|
4月前
|
SQL 缓存 Java
使用MyBatis优化Java持久层操作
使用MyBatis优化Java持久层操作
|
5月前
|
Java 数据库连接 数据库
Spring日志完结篇,MyBatis操作数据库(入门)
Spring日志完结篇,MyBatis操作数据库(入门)
|
5月前
|
SQL Java 数据库连接
【MyBatis】深入解析MyBatis:高效操作数据库技术详解
【MyBatis】深入解析MyBatis:高效操作数据库技术详解
43 0
|
5月前
|
SQL Java 数据库连接
【MyBatis】MyBatis操作数据库(二):动态SQL、#{}与${}的区别
【MyBatis】MyBatis操作数据库(二):动态SQL、#{}与${}的区别
60 0
|
6月前
|
SQL Java 数据库连接
MyBatis 操作数据库
MyBatis 操作数据库