Mybatis高级

1. Mybatis多表查询概念

​ 在学习多表查询的之前,我们要先明确多表的关系都有哪些,如何划分。

1.1 多表关系的划分

一对一

一对一的关系是两张表之间 A表的一条数据只能对应B表的一条数据。比如 订单表和用户表 一个订单只能属于一个用户,所以是一对一的关系。

一对多

一对多的关系是两张表之间 A表的一条数据可以对应B表的多条数据。比如用户表和订单表, 一个用户可以拥有多个订单,所以是一对多的关系

多对多

多对多的关系是两张表之前 A表的一条数据可以对应B表的多条数据,反之,B表的数据也可 以对应A表的多条数据,但这只是在业务理解层面的意义。实际上两张表如果是多对多的关 系,那么这两张表不能直接关联,需要一张中间表来联系起来。

划分表关系的技巧

  1. 先从业务层面理解2张表的关系,然后看需求要查询的主表是哪张表

  2. 比如订单表和用户表,如果从订单的表的角度来看,那么就是一对一,如果从用户的角度来看,那么就是一对多

  3. 看需求:如果需求是查询订单表以及关联查询该订单的所属用户,那么就是一对一,如果是查询用户以及关联查询该用户的订单,那么就是一对多

  4. 在写之前一定要明确表关系!不然怎么写都是错的。

  5. 多表关系大多数都是通过id字段来关联的

  6. 其实多对多的需求本质上就是双向的一对多

1.2表关系划分的练习

  1. 文章表和评论表

从文章表的角度来看 是1对多

从评论表的角度来看 是1对1

  1. 学生表和班级表

从学生表的角度来看 是1对1

从班级表点的角度来看 是1对多

  1. 用户表和角色表

从用户表的角度来看 是1对多

从角色表的角度来看 是1对多

表的关系是 多对多

  1. 用户表和身份证表

从用户表的角度来看 是1对1

从身份证表的角度来看 是1对1

表的关系是1对1

  1. 桌子表和椅子表

从桌子的角度来看 1对多

从椅子的角度来看 1对1

2. Mybatis多表查询

​ Mybatis多表查询,只要编写好Sql语句,设置好查询结果的映射就非常简单了

2.1 一对一查询

​ 已知有用户表和订单表 表结构如下

​ 需求:

查询出订单信息,并且查询出每个订单信息所属的用户信息

分析表关系

从订单表角度来看,那就是一对一

订单表的uid字段 代表 所属用户的id 和用户表的id关联

2.1.1 查询的sql语句

select * from orders o ,user u where o.uid = u.id

2.1.2 创建实体类

在订单类中声明一个用户对象

public class Order {

    private int id;
    private Date ordertime;
    private double total;
    //代表当前订单从属于哪一个客户
    private User user;
    //省略set get。。。。
}

public class User {
    
    private int id;
    private String username;
    private String password;
    private String birthday;
	//省略set

2.1.3 创建IOrderMapper接口

public interface OrderMapper {
    List<Order> findAll();
}

2.1.4 创建OrderMapper.xml文件

​ 方式一

<mapper namespace="com.demo.mapper.OrderMapper">
	<resultMap id="orderMap" type="com.demo.bean.Orders">
        <result column="username" property="user.username"></result>
        <result column="password" property="user.password"></result>
        <result column="birthday" property="user.birthday"></result>
    </resultMap>
    <select id="findAll" resultMap="orderMap">
        select * from orders o,user u where o.uid=u.id
    </select>
</mapper>

方式二

<resultMap id="orderMap" type="com.demo.bean.Orders">
        <result property="id" column="id"></result>
        <result property="ordertime" column="ordertime"></result>
        <result property="total" column="total"></result>
        <result property="uid" column="uid"></result>
        <association property="user" javaType="com.demo.bean.User">
            <result property="id" column="id"></result>
            <result column="username" property="username"></result>
            <result column="password" property="password"></result>
            <result column="birthday" property="birthday"></result>
        </association>
    </resultMap>

resutMap知识点:

作用:

  1. 当表中的列名和类中的属性名 不一致的时候 可以手动的修改映射

  2. 做多表查询的时候 给表中没有的字段 但是类中有的属性赋值

一对一:

2种方式映射

  1. <resultMap> + <association>

  2. 直接用<resultMap>种的<result>

  3. 强烈推荐使用第一种

2.1.5 测试结果

编写单元测试 通过mapper调用方法 查看结果

//查询全部订单信息 包含用户
    @Test
    public void findAllOrders(){
        List<Orders> ordersList = mapper.findAllOrder();
        //遍历结果
        for (Orders orders : ordersList) {
            System.out.println(orders);
        }
    }

2.2 一对多查询

同样还是上面的订单表和用户表

需求:

查询每个用户以及该用户关联的订单列表

分析表关系

从用户表角度来看,那就是一对多

用户表的主键id和订单表的uid进行关联

2.2.1 查询的Sql语句

select *,o.id oid from user u left join orders o on u.id=o.uid;

一对多的查询 其实可以和一对一的查询同样的sql 但是不建议。建议使用左连接来查询。

2.2.2 修改实体类

​ 在User实体类中声明一个代表订单的集合

public class User {
	private Integer id;
	private String username;
	private String password;
	private String birthday;
	private List<Orders> ordersList;
}

2.2.3 创建IUserMapper接口

public interface IUserMapper {
    List<User> findAll();
}

2.2.4 创建UserMapper.xml文件

<mapper namespace="com.demo.mapper.IUserMapper">
    <resultMap id="userMap" type="com.zrrd.bean.User">
        <result column="id" property="id"></result>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birthday" property="birthday"></result>
        <collection property="ordersList" ofType="com.demo.bean.Orders">
            <result column="uid" property="uid"></result>
            <result column="ordertime" property="ordertime"></result>
            <result column="total" property="total"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
        select * from user u left join orders o on u.id=o.uid
    </select>
</mapper>

2.2.5 测试结果

编写单元测试 通过mapper调用方法 查看结果

//查询全部订单信息 包含用户
    @Test
    public void findAllOrders(){
        List<User> userList = mapper.findAllUser();
        for (User user : userList) {
            System.out.println("当前用户:"+user.getUsername());
            System.out.println("关联订单:"+user.getOrdersList());
            System.out.println("================================");
        }
    }

小总结:

1对1和1对多的写法区别:

  1. 一对一用<resultMap> + <association> 用javaType

  2. 一对多用<resultMap> + <collection> 用ofType

2.3 多对多查询

完成学生表和课程表的需求

学生表(id name age sex )

课程表(id name hour)

多对多表之间不能有直接关联 要创建中间表

中间表(id sid cid)

需求:

查询每个学生的信息以及学生学习了哪些课程

查询每个课程的信息以及课程被哪些学生学习了

表关系分析:

其实多对多直接可以拆分成一对多

从学生表的角度查询 一对多

从课程表的角度查询 一对多

2.3.1 查询的sql语句

select * from student s left join stu_cour sc on sc.sid = s.id inner join course c on sc.cid = c.id

参照一对多的写法 完成功能

步骤:

  1. 创建实体类和接口

  2. 编写核心配置文件MapperConfig

  3. 分别创建Mapper映射文件并编写返回的resultMap

  4. 测试结果

实操:

  1. 创建实体类

    public class Student {

     private Integer id;
     private String name;
     private Integer age;
     private String sex;
     //关联的课程集合
     private List<Course> courseList;
     省略 get和set方法
    

    }

    public class Course {
    private Integer id;
    private String name;
    private Integer hour;
    //关联的学生的集合
    private List<Student> studentList;
    省略get和set方法
    }

创建接口

public interface StudentMapper {
    //查询全部学生 并且查询出学生关联的课程集合
    List<Student> findAllStudent();
}

public interface CourseMapper {
    //查询全部学生 并且查询出学生关联的课程集合
    List<Course> findAllCouerse();
}

关联查询情况:

  1. 编写核心配置文件MapperConfig

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration>
     <!--加载其他的配置文件-->
     <properties resource="jdbcConfig.properties"></properties>
     <!--给实体类起别名-->
     <typeAliases>
         <typeAlias type="com.demo.bean.Student" alias="s"></typeAlias>
         <typeAlias type="com.demo.bean.Course" alias="c"></typeAlias>
     </typeAliases>
     <!--必须要放这里不然报错-->
     <plugins>
         <!-- 注意:分页助手的插件  配置在通用馆mapper之前 -->
         <plugin interceptor="com.github.pagehelper.PageHelper">
             <!-- 指定方言 -->
             <property name="dialect" value="mysql"/>
         </plugin>
     </plugins>
     <environments default="development">
         <environment id="development">
             <transactionManager type="JDBC"/>
             <dataSource type="POOLED">
                 <property name="driver" value="${jdbc.driver}"/>
                 <property name="url" value="${jdbc.url}"/>
                 <property name="username" value="${jdbc.username}"/>
                 <property name="password" value="${jdbc.password}"/>
             </dataSource>
         </environment>
     </environments>
    
     <mappers>
         <mapper resource="StudentMapper.xml"/>
         <mapper resource="CourseMapper.xml"/>
     </mappers>
    
    </configuration>
  2. 分别创建Mapper映射文件并编写返回的resultMap

    <mapper namespace="com.demo.mapper.StudentMapper">
     <resultMap id="studenrtMap" type="s">
         <result column="id" property="id"></result>
         <result column="name" property="name"></result>
         <result column="age" property="age"></result>
         <result column="sex" property="sex"></result>
         <collection property="courseList" ofType="c">
             <result column="cid" property="id"></result>
             <result column="cname" property="name"></result>
             <result column="chour" property="hour"></result>
         </collection>
     </resultMap>
    
     <!--查询全部学生   需要起别名,因为两个表id都是这个属性名,name也是相同属性名,容易识别不出来-->
     <select id="findAllStudent" resultMap="studenrtMap">
         select s.*,c.id cid,c.name cname,c.hour chour from student s left join stu_cour sc on s.id = sc.sid inner join
                       course c on c.id = sc.cid;
     </select>
    
    </mapper> <mapper namespace="com.demo.mapper.CourseMapper">
     <resultMap id="courseMap" type="c">
         <result column="id" property="id"></result>
         <result column="name" property="name"></result>
         <result column="hour" property="hour"></result>
         <collection property="studentList" ofType="s">
             <result column="sid" property="id"></result>
             <result column="sname" property="name"></result>
             <result column="sage" property="age"></result>
             <result column="ssex" property="sex"></result>
         </collection>
     </resultMap>
    
     <select id="findAllCouerse" resultMap="courseMap">
         select c.*,
                s.id sid,
                s.name sname,
                s.age sage,
                s.sex ssex
         from course c
                  left join stu_cour sc on c.id = sc.cid
                  inner join student s
                             on s.id = sc.sid;
     </select>
    
    </mapper>
  3. 测试结果

    public class StudentTest {
    SqlSession sqlSession;
    StudentMapper mapper;
    @Before
    public void init() throws IOException {
    //加载核心配置文件
    InputStream stream = Resources.getResourceAsStream("MapperConfig.xml");
    //创建Sqlseesion工厂对象
    SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(stream);
    //通过工厂对象 获取Sqlseesion对象
    sqlSession = ssf.openSession();
    //获取Mapper对象
    mapper = sqlSession.getMapper(StudentMapper.class);
    }

     //查询全部订单信息 包含用户
     @Test
     public void findAllOrders(){
         List<Student> students = mapper.findAllStudent();
         for (Student student : students) {
             System.out.println("学生姓名:"+student.getName());
             System.out.print("学习课程:");
             List<Course> courseList = student.getCourseList();
             for (Course course : courseList) {
                 System.out.print(course.getName()+"\t");
             }
             System.out.println();
         }
     }
    
     @After
     public void close(){
         //提交事务
         sqlSession.commit();
         //关闭资源
         sqlSession.close();
     }
    

    }

    public class CourseTest {
    SqlSession sqlSession;
    CourseMapper mapper;
    @Before
    public void init() throws IOException {
    //加载核心配置文件
    InputStream stream = Resources.getResourceAsStream("MapperConfig.xml");
    //创建Sqlseesion工厂对象
    SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(stream);
    //通过工厂对象 获取Sqlseesion对象
    sqlSession = ssf.openSession();
    //获取Mapper对象
    mapper = sqlSession.getMapper(CourseMapper.class);
    }

     //查询全部订单信息 包含用户
     @Test
     public void findAllOrders(){
         List<Course> couerseList = mapper.findAllCouerse();
         for (Course course : couerseList) {
             System.out.println("课程名称:"+course.getName());
             System.out.println("课程学生:"+course.getStudentList());
         }
     }
    
     @After
     public void close(){
         //提交事务
         sqlSession.commit();
         //关闭资源
         sqlSession.close();
     }
    

    }

相关推荐
LightOfNight21 分钟前
Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)
服务器·数据库·redis·分布式·后端·缓存·中间件
代码中の快捷键34 分钟前
MySQL数据库存储引擎的数据结构
数据结构·数据库·mysql
Adolf_19931 小时前
Django 路由层
数据库
好记忆不如烂笔头abc1 小时前
logminer挖掘日志归档查找问题
数据库·sql·mysql
java_heartLake9 小时前
PostgreSQL数据库参数调优实践
数据库·postgresql·调优
xnuscd10 小时前
Milvus概念
数据库·学习·mysql
代码欢乐豆10 小时前
软件工程第13章小测
服务器·前端·数据库·软件工程
小gpt&11 小时前
实现qt拖拽显示或者播放
数据库·qt·音视频
望获linux11 小时前
在 ARM 平台上如何实现Linux系统的1秒启动
linux·服务器·开发语言·数据库·操作系统·嵌入式操作系统·arm平台
漫天转悠11 小时前
MySQL 七种JOIN连接详解
数据库·mysql