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();
     }
    

    }

相关推荐
毕业设计制作和分享1 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
ketil271 小时前
Redis - String 字符串
数据库·redis·缓存
Hsu_kk2 小时前
MySQL 批量删除海量数据的几种方法
数据库·mysql
编程学无止境2 小时前
第02章 MySQL环境搭建
数据库·mysql
knight-n2 小时前
MYSQL库的操作
数据库·mysql
包饭厅咸鱼3 小时前
QML----复制指定下标的ListModel数据
开发语言·数据库
生命几十年3万天3 小时前
redis时间优化
数据库·redis·缓存
Elastic 中国社区官方博客3 小时前
释放专利力量:Patently 如何利用向量搜索和 NLP 简化协作
大数据·数据库·人工智能·elasticsearch·搜索引擎·自然语言处理
力姆泰克4 小时前
看电动缸是如何提高农机的自动化水平
大数据·运维·服务器·数据库·人工智能·自动化·1024程序员节
力姆泰克4 小时前
力姆泰克电动缸助力农业机械装备,提高农机的自动化水平
大数据·服务器·数据库·人工智能·1024程序员节