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

2. 学生表和班级表
            从学生表的角度来看 是1对1
            从班级表点的角度来看 是1对多

3. 用户表和角色表
            从用户表的角度来看 是1对多
            从角色表的角度来看 是1对多
            表的关系是 多对多

4. 用户表和身份证表
            从用户表的角度来看 是1对1
            从身份证表的角度来看 是1对1
            表的关系是1对1
5. 桌子表和椅子表
            从桌子的角度来看 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();
}

关联查询情况: 

  2. 编写核心配置文件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>

3. 分别创建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>

4. 测试结果

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

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis中,高级查询可以使用延迟加载机制来实现。延迟加载是将数据加载时机推迟,例如推迟嵌套查询的执行时机。通过延迟加载,可以先查询主表,按需实时做关联查询,返回关联表结果集,提高效率。 在MyBatis中,实现关联查询有两种不同的方式:嵌套Select查询和嵌套结果映射。嵌套Select查询是通过执行另外一个SQL映射语句来加载期望的复杂类型,而嵌套结果映射则使用嵌套的结果映射来处理连接结果的重复子集。 对于关联结果映射和其他类型的映射,工作方式类似。需要指定目标属性名以及属性的javaType,大多数情况下MyBatis可以推断出来,如果需要的话,还可以设置JDBC类型。如果想要覆盖获取结果值的过程,可以设置类型处理器。 综上所述,通过延迟加载机制和适当的关联查询方式,MyBatis可以实现高级查询功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mybatis高级查询](https://blog.csdn.net/weixin_37650458/article/details/96587906)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [MyBatis高级查询](https://blog.csdn.net/qq_66991094/article/details/127147576)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值