Day66.关联映射: 连接查询、分步查询、延迟加载,动态SQL语句: if where、foreach、set

目录

映射关联关系

一、关联关系概念说明

二、关键词总结

三、创建模型

四、连接查询 (JOIN多表查询)

1、一对一 & 多对一

2、一对多 & 多对多(集合)

五、分步查询

六、延迟加载(懒加载)

七、多对多关联和一对一关联

动态SQL语句

一、if 和 where标签(重点)

二、trim标签 (了解)

三、choose/when/otherwise标签 (不常用)

四、foreach标签 

五、set标签

六、sql标签(了解)

多对多关联映射 Student练习:多表连接、分步查询、延迟加载

一、准备工作、数据库表、实体类

二、 多表连接方式

三、分布查询、延迟加载方式


映射关联关系

在实际开发中,经常会将来自多张表的数据在一个位置显示。比如查询并显示的员工信息中会有来自部门表、岗位表的数据,而后台一般只定义一个方法
List<User> findUser(conditions); 这就要求User中要包含部门Dept、岗位Position的信息;

556f879757934ac9b71fb68ce268504c.png

在MyBatis中是如何实现对多表的查询并实现数据的组装呢?(此处就没有DML操作什么事了)。 主要可以通过两种方式来实现,以顾客表Customer和订单表Order为例进行讲解。

(1)连接查询只需执行一条SQL语句,效率高不灵活只有立即加载没有延迟加载

(2)分步查询需执行多条SQL语句,效率低灵活可设置立即还是延迟

一、关联关系概念说明

① 数量关系

主要体现在数据库表中,不管哪种关系,都是通过外键搞定。

  • 一对一:人和身份证 (需要给外键加唯一约束,将一对一变成一对多)
  • 一对多:部门和员工,客户和订单
  • 多对多:学生和课程,老师和学生 (需要引入一个中间表)

② 关联关系的方向        (待修改,例子改为员工部门)

  • 双向双方都可以访问到对方 
            Customer:包含Order的集合属性
            Order:包含单个Customer的属性
  • 单向双方中只有一方能够访问到对方
            Customer:不包含Order的集合属性,访问不到Order
            Order:包含单个Customer的属性、
  • 数据库之间建立关联关系通过外键
  • 实体类之间建立关联关系通过成员变量

二、关键词总结

关联关系配置项关键词所在配置文件
对一association 标签/ javaType 属性Mapper配置文件中的 resultMap
对多collection 标签/ ofType 属性Mapper配置文件中的 resultMap
对一分步association 标签/ select 属性Mapper配置文件中的 resultMap
对多分步collection 标签/ select 属性Mapper配置文件中的 resultMap
延迟加载[低]lazyLoadingEnabled 设置为true
aggressiveLazyLoading 设置为false
Mybatis全局配置文件中的 settings
延迟加载[高]lazyLoadingEnabled 设置为trueMybatis全局配置文件中的 settings

三、创建模型

①创建数据库表插入测试数据

CREATE TABLE `t_customer` (
     `customer_id` INT NOT NULL AUTO_INCREMENT, 
     `customer_name` CHAR(100), 
     PRIMARY KEY (`customer_id`) 
);
CREATE TABLE `t_order` ( 
    `order_id` INT NOT NULL AUTO_INCREMENT, 
    `order_name` CHAR(100), 
    `customer_id` INT, 
    PRIMARY KEY (`order_id`) 
); 
INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1'); 
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1'); 
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); 

②创建实体类

//顾客类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    private Integer customerId; //客户编号
    private String customerName;//客户姓名
    //客户信息中可以知道该客户的所有订单
    private List<Order> orderList = new ArrayList<>();
}
//订单类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    private Integer orderId;
    private String orderName;
    //一般保留,添加使用
    private Integer customerId;
    //订单知道所属的客户详细信息,查询使用
    private Customer customer;
}

实际开发时,一般在开发过程中,不给数据库表设置外键约束。

原因是避免调试不方便。

一般是功能开发完成,再加外键约束检查是否有bug。

③Mapper接口和映射文件

 eda2c646038748e686a3ad34a3b0c8e8.png
Mapper.xml 需要填写命名空间,Mapper接口全类名。
mybatis_config.xml全局配置需要指定映射文件路径。

mybatis-config.xml中注册Mapper配置文件
    <mappers>
        <!-- 指定映射文件的路径 -->
        <mapper resource="mapper/CustomerMapper.xml"/>
        <mapper resource="mapper/OrderMapper.xml"/>
    </mappers>

四、连接查询 (JOIN多表查询)

1、一对一 & 多对一

查询某个订单的信息,携带客户的信息。(多对一)

关键词:association 、javaType

注意1:使用join连接查询,即使属性名和字段相同,映射也不能少

注意2:使用join连接查询,配置文件中配置了驼峰命名映射,映射也不能少

注意3:关联的映射要使用 association

注意4:javaType="com.atguigu.pojo.Customer" 可以省略

Mapper接口

public interface OrderMapper {
    //查询指定编号的订单信息(携带客户的信息)
    Order selectOrderWithCustomer(Integer orderId);
}

Mapper映射文件

<mapper namespace="com.atguigu.mapper.OrderMapper">
    <select id="selectOrderWithCustomer" resultMap="orderMap">
        SELECT *
        FROM t_order o
        JOIN t_customer c
        ON o.customer_id = c.customer_id
        WHERE o.order_id = #{orderId}
    </select>
    <resultMap id="orderMap" type="order">
        <id column="order_id" property="orderId"></id>
        <result column="order_name" property="orderName"></result>
        <result column="customer_id" property="customerId"></result>
        <!--关键 关联的映射--> <!--javaType可以省略-->
        <association property="customer" javaType="com.atguigu.pojo.Customer">
            <id column="customer_id" property="customerId"></id>
            <result column="customer_name" property="customerName" ></result>
        </association>
    </resultMap>
</mapper>

测试类

    @Test
    public void testSelectOrderWithCustomer(){
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        Order order = mapper.selectOrderWithCustomer(1);
        System.out.println(order);
        System.out.println(order.getCustomer());
    }

2a71595893ff42e0af8f42697c01e426.png

2、一对多 & 多对多(集合)

查询某个客户的信息,携带其多个订单信息 ( 一对多 )

关键词:collection 、 ofType

Mapper接口

public interface CustomerMapper {
    //查询某个客户的信息(携带其多个订单信息)
    Customer selectCustomerWithOrderList(Integer customerId);

}

Mapper映射文件

<mapper namespace="com.atguigu.mapper.CustomerMapper">
    <!--查询某个客户的信息(携带其多个订单信息)-->
    <select id="selectCustomerWithOrderList" resultMap="customerMap">
        SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
        FROM t_customer c
        JOIN t_order o
        ON c.customer_id = o.customer_id
        WHERE c.customer_id = #{customerId}
    </select>
    <resultMap id="customerMap" type="customer">
        <id column="customer_id" property="customerId"></id>
        <result column="customer_name" property="customerName"></result>
        <collection property="orderList" ofType="order"><!--别名-->
            <id column="order_id" property="orderId"></id>
            <result column="order_name" property="orderName"></result>
        </collection>
    </resultMap>
</mapper>

测试类

    //查询某个客户的信息(携带其多个订单信息)
    @Test
    public void testSelectCustomerWithOrderList(){
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customer = mapper.selectCustomerWithOrderList(1);
        System.out.println(customer);
        System.out.println(customer.getOrderList());
    }

d5ae617123e342dea18cdd8dd85eedb2.png

总结:

多表连接查询的优点

  1. 一条SQL语句查询多张表,结果包含多张表的数据
  2. 速度快

多表连接查询的缺点

  1. 如果只想获取一张表的数据,但是多张表也会查询出来(效率低)
  2. 对于一对多来说,这个问题更严重。只要客户名称,不要订单列表,却把订单列表(这是一个集合,多条记录)也查出来。

解决:

  1. 多写几个Sql,完成不同的功能。
  2. 可以采用更加灵活的延迟加载。要使用延迟加载,必须先使用分步查询

五、分步查询

连接查询缺点:不灵活。只有立即加载,没有延迟加载。数据不管是否需要,都会查询出来。

解决:如果不确定是否需要,可以采用更加灵活的延迟加载。要使用延迟加载,必须先将连接查询 (一条SQL)  拆分为分步查询 (多条SQL语句)

案例:查询客户信息,可能要查看订单信息,也可能不查看订单信息.

准备1:查询指定编号的客户(不带订单 单表查询)

public interface CustomerMapper {
    //单表查询
    Customer findById(Integer customerId);
}
    <!--分布查询,查询客户--><!--使用了驼峰命名自动匹配-->
    <select id="findById" resultType="customer">
        SELECT *
        FROM t_customer
        WHERE customer_id = #{customerId}
    </select>
    @Test
    public void testFindById(){
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customer = mapper.findById(1);
        System.out.println(customer);
    }

准备2:查询指定编号的客户的订单 (只有订单,单表)

public interface OrderMapper {
    //查询指定编号的订单信息(携带客户的信息)
    Order selectOrderWithCustomer(Integer orderId);
}
    <!--分布查询,查询用户订单--><!--使用了驼峰命名自动匹配-->
    <select id="selectOrderList" resultType="order">
        SELECT *
        FROM t_order
        WHERE customer_id = #{customerId}
    </select>
    //分布查询准备: 查询指定客户的所有订单(单表)
    @Test
    public void testSelectOrderList(){
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        List<Order> orders = mapper.selectOrderList(1);
        orders.forEach(order -> System.out.println(order));
    }

注意:

1.上面进行了两个单表查询,使用的是ResultType,而不是ResultMap

2.单表查询,使用自动驼峰命名规则可以简化操作,不用手动别名。
<setting name="mapUnderscoreToCamelCase" value="true"/>

实现以上两个单独操作的合并

    select id="findById2" resultMap="customerMap2">
        SELECT *
        FROM t_customer
        WHERE customer_id = #{customerId}
    </select>
    <resultMap id="customerMap2" type="customer">
        <id column="customer_id" property="customerId"></id>
        <result column="customer_name" property="customerName"></result>
        <collection  select="com.atguigu.mapper.OrderMapper.selectOrderList"
                     column="customer_id"
                     property="orderList"></collection>
    </resultMap>

分步查询是延迟加载的前提。

六、延迟加载(懒加载)

延迟加载:对于实体类关联的属性到需要使用时才查询。也叫 懒加载

lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态
  • 第一步:开启延迟加载(lazyload  懒加载)全局开关并测试

注意:由于分开关的优先级高于总开关,总开关为false,分开关 fetchType="lazy" 也可以开启懒加载。lazy | eager

  mybatis-config.xml
    <settings>
        <!--配置懒加载总开关 默认值false不开启-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    @Test
    public void testFindById2(){
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customer = mapper.findById2(1);
        //System.out.println(customer);
        //不执行第二步查询,只查询了客户信息
        System.out.println(customer.getCustomerName());
        System.out.println("--------------------------");
        //只有需要获取订单信息时,才会发起第二步查询
        System.out.println(customer.getOrderList());
    }

第二步:开启分开关:fetchType 并测试

resultMap 映射中加入参数 fetchType="eager" ,立即查询,饥饿加载。执行所有的分步查询。

    <!--分步查询-->
    <select id="findById2" resultMap="customerMap2">
        SELECT *
        FROM t_customer
        WHERE customer_id = #{customerId}
    </select>
    <resultMap id="customerMap2" type="customer">
        <id column="customer_id" property="customerId"></id>
        <result column="customer_name" property="customerName"></result>
        <collection  select="com.atguigu.mapper.OrderMapper.selectOrderList" 
                     column="customer_id"
                     property="orderList"
                     fetchType="eager"
        ></collection>
    </resultMap>

总开关设置false,分开关设置 fetchType="lazy",开启懒加载,分布查询。

select = "com.atguigu.mapper.OrderMapper.selectOrderList"  指定要引用的SQL语句
column = "customer_id"     建立关联关系时所依赖的字段
property = "orderList"         查询的成员变量
fetchType = "eager"            懒加载分开关

七、多对多关联和一对一关联

  • 多对多

1、在数据库中,通过引入一个中间表,将一个多对多变成两个一对多

2、在Java类中

方案一:可以象数据库表一样,定义三个实体类

方案二:还可以在Java类中直接建立多对多关系 (List集合),映射文件中均使用Collection进行映射。


  • 一对一

1、数据库中使用外键搞定

方案1:外键关联:将外键同时设为unique,将一对多变成了一对一

方案2:主键关联:同时是主键和外键。主键保证了唯一和非空;外键保证了必须参考Person类的主键。不允许现有身份证号,再有人。

2、实体类中

在MyBatis中如何表示一对一;

Person类: IdCard idcard;

IdCard类:Person  person;

两端的映射文件中都使用association。

多对多加集合 ,一对一加对象

动态SQL语句

经常遇到很多按照很多查询条件进行查询的情况,比如智联招聘的职位搜索,比如OA系统中的支出查询等。其中经常出现很多条件不取值的情况,在后台应该如何完成最终的SQL语句呢?

在使用JABC中,一般情况下是使用StringBuilder类及其append方法实现。利用动态 SQL 这一特性可以彻底避免字符串频繁拼接的痛苦。

MyBatis在简化操作方法提出了动态SQL功能,将使用Java代码拼接SQL语句,改变为在XML映射文件中截止标签拼接SQL语句。相比而言,大大减少了代码量,更灵活、高度可配置、利于后期维护。动态SQL语句不需要拼接代码,只需要在xml映射文件中进行配置,利于修改

MyBatis也可以在注解中配置SQL,但是由于注解功能受限,尤其是对于复杂的SQL语句,可读性很差,所以较少使用

一、if 和 where标签(重点)

//if语句
public List<Employee> findEmp(@Param("empName") String empName, @Param("minSalary") Double minSalary);
//where语句
public List<Employee> findEmp2(@Param("empName") String empName, @Param("minSalary") Double minSalary);
    <!-- if 1=1 避免一个第一个条件没有触发,and报错-->
    <select id="findEmp" resultType="employee">
        select * from t_emp where 1=1
        <if test="empName!=null and empName!=''">
            and emp_name like "%"#{empName}"%"
        </if>
        <if test="minSalary>0">
            and emp_salary >= #{minSalary}
        </if>
    </select>

    <!--where 会自动去掉多余的and / or-->
    <select id="findEmp2" resultType="employee">
        select * from t_emp
        <where>
            <if test="empName!=null and empName!=''">
                and emp_name like "%"#{empName}"%"
            </if>
            <if test="minSalary>0">
                and emp_salary >= #{minSalary}
            </if>
        </where>
    </select>

小技巧:where 1= 1 让其他条件都不是第一个条件,都以and开始

二、trim标签 (了解)

使用trim标签控制条件部分两端是否包含某些字符

  • prefix 属性:指定要动态添加的前缀

  • suffix 属性:指定要动态添加的后缀

  • prefixOverrides 属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值

  • suffixOverrides 属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值

public List<Employee> findEmp3(@Param("empName") String empName, @Param("minSalary") Double minSalary);
    //trim
    @Test
    public void testFindEmp3(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        //List<Employee> emp = mapper.findEmp(null, 0.0);
        List<Employee> emp = mapper.findEmp2("李", 1000.0);
        emp.forEach(employee -> System.out.println(employee));
    }
    <!--trim-->
    <select id="findEmp3" resultType="employee">
        select * from t_emp
        <trim prefix="where" prefixOverrides="and">
            <if test="empName!=null and empName!=''">
                and emp_name like "%"#{empName}"%"
            </if>
            <if test="minSalary>0">
                and emp_salary >= #{minSalary}
            </if>
        </trim>
    </select>

三、choose/when/otherwise标签 (不常用)

不管有几个条件,最多满足一个如果一个也不满足,执行otherwise的条件

    //4.choose/when/otherwise标签(switch case)
    public List<Employee> findEmp4(@Param("empName") String empName, @Param("minSalary") Double minSalary);
<!--choose-->
    <select id="findEmp4" resultType="employee">
        select * from t_emp where
        <!--相当于switch case,不管有多少分支,最多执行一个-->
        <choose>
            <when test="empName!=null and empName!=''">
                emp_name like "%"#{empName}"%"
            </when>
            <when test="minSalary>0">
                emp_salary >= #{minSalary}
            </when>
            <otherwise>
                1=1  <!--防止条件都不满足,where多余-->
            </otherwise>
        </choose>
    </select>

四、foreach标签 

注意关于foreach标签的collection属性。

如果数组参数没有使用@Param,collection使用 array

如果集合参数没有使用@Param,collection使用list、collection

    //5.foreach
    public List<Employee> findEmp5(@Param("idArr") int [] idArr);
    public List<Employee> findEmp6(@Param("idList")List<Integer> idList);
    //注意,没有使用@Param
    public void saveEmps(List<Employee> empList);
    <!--foreach-->
    <!--传参数组-->
    <select id="findEmp5" resultType="employee">
        SELECT * FROM t_emp
        WHERE emp_id IN
        <!--没有指定@Param,使用array-->
        <foreach collection="idArr" separator="," open="(" close=")" item="elem">
            #{elem}
        </foreach>
    </select>
    <!--传参集合-->
    <select id="findEmp6" resultType="employee">
        SELECT * FROM t_emp
        WHERE emp_id IN
        <!--没有指定@Param,使用collection、list-->
        <foreach collection="idList" separator="," open="(" close=")" item="elem">
            #{elem}
        </foreach>
    </select>
    <!--批量添加-->
    <insert id="saveEmps">
        INSERT INTO t_emp
        <!--没有指定@Param,使用collection、list-->
        <foreach collection="list" separator="," open="VALUES" item="emp">
            (null,#{emp.empName},#{emp.empSalary})
        </foreach>
    </insert>
    //foreach
    @Test//传数组
    public void testFindEmp5(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        int[] idArr = {2,11,17,100};
        List<Employee> emp = mapper.findEmp5(idArr);
        emp.forEach(employee -> System.out.println(employee));
    }
    @Test//传集合
    public void testFindEmp6(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Integer> idList = new ArrayList<>();
        Collections.addAll(idList,2,11,17,100);
        List<Employee> emp = mapper.findEmp6(idList);
        emp.forEach(employee -> System.out.println(employee));
    }
    @Test//批量添加
    public void testSaveEmps(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        ArrayList<Employee> empList = new ArrayList<>();
        empList.add(new Employee(null,"白鼠1",123.0));
        empList.add(new Employee(null,"白鼠2",123.0));
        empList.add(new Employee(null,"白鼠3",123.0));
        mapper.saveEmps(empList);
    }

五、set标签

实际开发时,对一个实体类对象进行更新。往往不是更新所有字段,而是更新一部分字段

针对update操作,会自动的去掉多余的 ","

    public int updateEmp(Employee emp);
    <!--set-->
    <update id="updateEmp">
        UPDATE t_emp
        <set>
            <if test="empName!=null and empName!=''"><!--注意逗号要加上,没用会自动去掉-->
                emp_name = #{empName},
            </if>
            <if test="empSalary!=null and empSalary>0">
                emp_salary = #{empSalary}
            </if>
        </set>
        WHERE emp_id = #{empId}
    </update>
    @Test
    public void testUpdateEmp(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee emp = new Employee(25, null , 1000.0);
        mapper.updateEmp(emp);
    }

每年旅游要用

六、sql标签(了解)

提取SQL语句的公共部门,并使用include标签来引用。便于修改。

企业实际开发中,使用最多的其实是resultMap

<sql id="empColumns">
    emp_id empId,emp_name empName,emp_salary empSalary
</sql>
调用
<select id="findEmp" resultType="employee">
    select <include refid="empColumns"/>  from t_emp 
</select>

多对多关联映射 Student练习:多表连接、分步查询、延迟加载

  1. 预备:创建数据库表学生表、课程表、学生选课表并添加测试数据
  2. 功能1:查询所有学生及其选课信息(Student中含所选择的Course信息)
  3. 功能2:查询某一门课程及其选课的学生(Course中含选这门课的Student信息)
  4. 使用级联(分步)查询和多表连接查询分别完成

提示:在Student、Course中分别添加List类型的成员变量,并且在映射文件中分别使用<collection>元素进行配置。

一、准备工作、数据库表、实体类

项目结构:

学生类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer studentId;
    private String studentName;
    private Integer studentAge;
    //学生选课信息
    private List<Course> courseList;
}
课程类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
    private Integer courseId;
    private String courseName;
    //学生信息
    private List<Student> studentList;
}

学生表

选课表 (连接学生、课程表)

课程表
 

二、 多表连接方式

1. 查询所有学生及其选课信息

<!--命名空间,必须是Mapper接口的完整路径-->
<mapper namespace="com.atguigu.mapper.StudentMapper">
    <!--多表连接查询 所有学生及其选课-->
    <select id="findStudentAll" resultMap="studentList">
        SELECT st.student_id,student_name,student_age,co.course_id,co.course_name
        FROM h_student st
             JOIN h_select se
                  ON st.student_id = se.student_id
             JOIN h_course co
                  ON se.course_id = co.course_id
    </select>
    <resultMap id="studentList" type="student">
        <id column="student_id" property="studentId"></id>
        <result column="student_name" property="studentName"></result>
        <result column="student_age" property="studentAge"></result>
        <collection property="courseList" ofType="course">
            <id column="course_id" property="courseId"></id>
            <result column="course_name" property="courseName"></result>
        </collection>
    </resultMap>
public interface StudentMapper {
    //多表连接查询
    List<Student> findStudentAll();
    //分表查询:查询所有学生及其选课
    @Test
    public void testFindStudentAll(){
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentAll = mapper.findStudentAll();
        studentAll.forEach(student -> System.out.println(student));
    }

2. 查询某一门课程及其选课的学生

<!--命名空间,必须是Mapper接口的完整路径-->
<mapper namespace="com.atguigu.mapper.CourseMapper">

    <!--多表连接查询 指定课程下的所有学生-->
    <select id="findCourseById" resultMap="courseList">
        SELECT co.course_id,co.course_name,st.student_id,st.student_name,st.student_age
        FROM h_course co
                 JOIN h_select se
                      ON co.course_id = se.course_id
                 JOIN h_student st
                      ON st.student_id = se.student_id
        WHERE co.course_id = #{courseId}
    </select>
    <resultMap id="courseList" type="course">
        <id column="course_id" property="courseId"></id>
        <result column="course_name" property="courseName"></result>
        <collection property="studentList" ofType="student">
            <id column="student_id" property="studentId"></id>
            <result column="student_name" property="studentName"></result>
            <result column="student_age" property="studentAge"></result>
        </collection>
    </resultMap>
public interface CourseMapper {
    //多表连接查询
    List<Course> findCourseById(Integer id);
    //分表查询:查询某一门课程及其学生
    @Test
    public void testFindCourseAll(){
        CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
        List<Course> courseAll = mapper.findCourseById(2);
        courseAll.forEach(course -> System.out.println(course));
    }

三、分布查询、延迟加载方式

1. 查询所有学生及其选课信息

StudentMapper.xml
    <!--分步查询 每个学生的课程-->
    <select id="findStudentAll2" resultMap="findStudents">
        SELECT *
        FROM h_student
    </select>
    <resultMap id="findStudents" type="student">
        <id column="student_id" property="studentId"></id>
        <result column="student_name" property="studentName"></result>
        <result column="student_age" property="studentAge"></result>
        <collection select="com.atguigu.mapper.CourseMapper.findCourse"
                    column="student_id"
                    property="courseList"
                    fetchType="lazy"><!--开启懒加载(延迟加载)-->
        </collection>
    </resultMap>
CourseMapper.xml
    <!--分步查询的分表 每个学生的课程-->
    <select id="findCourse" resultType="course">
        SELECT co.course_id,co.course_name
        FROM h_course co
                 JOIN h_select se
                      ON co.course_id = se.course_id
        WHERE se.student_id = #{studentId}
    </select>
public interface StudentMapper {
    //分步查询 每个学生的课程
    List<Student> findStudentAll2();
}
    //分步查询、延迟加载,每个学生和所选的课程
    @Test
    public void testFindStudent(){
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentAll = mapper.findStudentAll2();
        for (Student student : studentAll) {
            System.out.println(student.getCourseList());
            System.out.println(student.getStudentName());
            //SELECT * FROM h_student 懒加载
        }
    }

2. 查询某一门课程及其选课的学生

CourseMapper.xml
    <!--分步查询 查询指定课程下的所有学生-->
    <select id="findCourseById2" resultMap="findCourseByIds">
        SELECT *
        FROM h_course
        WHERE course_id = #{courseId}
    </select>
    <resultMap id="findCourseByIds" type="course">
        <id column="course_id" property="courseId"></id>
        <result column="course_name" property="courseName"></result>
        <collection  select="com.atguigu.mapper.StudentMapper.findStudentById"
                     column="course_id"
                     property="studentList">
            <!--开启了全局延迟加载 不用写 fetchType="lazy"-->
        </collection>
    </resultMap>
StudentMapper.xml
    <!--分步查询分表 查询指定课程下的所有学生-->
    <select id="findStudentById" resultType="student">
        SELECT st.student_id,st.student_name,st.student_age
        FROM h_student st
                 JOIN h_select se
                      ON st.student_id = se.student_id
        WHERE course_id = #{courseId}
    </select>
public interface CourseMapper {
    //分步查询 查询指定课程下的所有学生
    List<Course> findCourseById2(Integer id);
    //分步查询、延迟加载 查询指定课程下的所有学生
    @Test
    public void testFindCourseById2(){
        CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
        List<Course> courseAll = mapper.findCourseById2(2);
        for (Course course : courseAll) {
            /*List<Student> studentList = course.getStudentList();
            System.out.println(studentList);*/
            System.out.println(course.getCourseName());
            //SELECT * FROM h_course WHERE course_id = ? 懒加载
        }
    }

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值