Mybatis进阶

/*
请使用user.sql初始化Mybatis数据库
需求1:
查询所有Student
根据ID查询
需求2:
添加一个Student
需求3:
修改一个Student
需求4:
删除一个Student
需求5:
查询Student,数据库字段名和实体类属性名不一致
// 需求6:根据现有student对象属性的值查找学生
// 学生对象如果只设置了id属性的值,就通过id查询,
// 如果id和name属性都有值,那就根据id和name两个条件查询
// 如果id和name、age属性都有值,那就根据id和name、属性三个条件查询

select * from student where id=#{id} and name=#{name}

要根据条件不一样,生成不同的SQL语句
if(name =! null)

*/

0. ResultMap

解决数据库字段名和实体属性名不一致的问题

  • 本质:Mybatis能帮我们自动映射封装的原理,就是结果集的字段名要和实体的属性名一致

  • 方式1:SQL语句中起别名

  • 方式2:在核心配置文件settings中通过mapUnderscoreToCamelCase=true实现自动转换

  • 方式3:使用resultMap手动建立结果集字段名和实体属性名映射关系,映射配置文件中配置如下:

    <select id="findByMap" resultMap="baseStudent">
           select * from student
    </select>
    <!--
    	主要应用场景:多表关系中配置。因为单表用这个会比较麻烦。
        当结果集字段名和实体属性名不一致的是,
        可以通过resultMap标签把不一致的内容建立起映射关系
            id 当前手动映射的唯一标识,方便调用
            type  当前映射是基于哪个类
    		atuoMapping 自动映射同名字段,默认值为true
        如果结果集字段名和实体属性名一致,resultMap会自动完成映射,
        我们只需要手动建立起名称不一致的映射即可
         -->
        <resultMap id="baseStudent" type="com.itheima.domain.Student" autoMapping="true">
            <!--
            id 建立主键和对应实体属性的映射
            column  数据库主键名
            property    对应的实体的属性名
         -->
        <!--<id column="id" property="id"/>-->
        <!--
            result 建立非主键和对应实体属性的映射
            column  数据库非主键字段名
            property    对应的实体的属性名
         -->
        <result column="first_username" property="firstUsername"/>
        <!--<result column="age" property="age"/>-->
    </resultMap>
    

1. 动态SQL

Java根据用户的需求拼接SQL11/21

// select * from student where id=#{id} and name=#{name} and age=#{age}

//要根据条件不一样,生成不同的SQL语句
String sql = select * from student where 1=1
if(id =! null){
    and id = #{id}
}
if(name =! null){
    and name = #{name}
}
if(age =! null){
    and age = #{age}
}

Mybatis自动完成动态SQL的拼接,本质就是在Mybatis映射配置文件中使用标签来拼接SQL,思路和上面的一样,写法不同。

1.1 ifwhere标签(重点)

<select id="selectCondition" resultType="student" parameterType="student">    
    select * from student  
    <where>
        <if test="id != null">
            AND id = #{id}
        </if>
        <if test="name != null">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>

imag

1.2 foreach(了解)

select * from student where id in(3,4,5)
<select id="selectByIds" resultType="student" parameterType="list">
    select * from student
    <where>
        <foreach collection="list" open="id IN (" close=")" item="xxx" separator=",">
            #{xxx}
        </foreach>
    </where>
</select>

imag

1.3 choose&when&otherwise(了解)

<!-- 需求:根据提供的条件查询,如果提供了id,就按id查询;如果没有提供id提供了name,就只按name查询;两者都不提供,查询所有 -->
<select id="selectCondition2" resultType="com.itheima.domain.Student">
    select * from student
    <where>
        <choose>
            <when test="id!=null">
                 id = #{id}
            </when>
            <when test="name!=null">
                 name = #{name}
            </when>
            <when test="age!=null">
                 age = #{age}
            </when>
            <otherwise>
                 1=1  [/ true]
            </otherwise>
        </choose>
    </where>
</select>

imag

1.4 set(了解)

// 需求4:动态更新Student,根据用户传的内容更新数据中某一行数据
void updateByCondition(Student stu);
<!-- 需求4:动态更新Student,根据用户传的内容更新数据中某一行数据
        set中的更新id,是为了避免没有需要更新字段时候,SQL语句拼接语法错误的问题
     -->
<update id="updateByCondition">
    update student
    <set>
        <if test="id != null">id=#{id}</if>
        <if test="name != null">name=#{name}</if>
        <if test="age != null">age=#{age},</if>
    </set>
    <where>
        id=#{id}
    </where>
</update>

在这里插入图片描述

1.5 SQL片段(重点)

<!--
    用于抽取SQL语句动的代码片段,效果类似于java的方法
    id  唯一标识,用于区分多个SQL片段,也用于使用的调用标志
    标签体编写抽取出来的SQL片段
    注意:
        可以统一修改,但是要谨慎。

-->
<sql id="xxx" >SELECT * FROM student</sql>


<!--
    include标签用于使用之前定义好的SQL片段  直接把该标签SQL语句中对应的位置即可
    refid   要引用的SQL片段的id
-->
<include refid="xxx"/>

<!--sql片段抽取-->
<sql id="columes">id, name, age</sql>

<select id="findByCondition" parameterType="user" resultType="user">
	select <include refid="columes"/> from student
</select>

2. 分页插件

2.1 分页语句写法

select * from student [where name like '%张%'] limit [之前页已经展示的记录数], 本页展示记录数;
-- 之前页已经展示的记录数 = (当前页数 - 1 )* 每页记录数

2.2 Mybatis分页插件

github地址:

https://github.com/pagehelper/Mybatis-PageHelper

2.3 实现分页的步骤

  1. 导入jar包(注意版本和视频中一致)

    jsqlparser-3.1.jar
    pagehelper-5.1.10.jar
    
  2. 在核心配置文件中配置分页助手插件

    <!--
        分页助手的插件
        插件中入口类的全限定类名
    	注意配置顺序,否则会报错
    	SAXParseException; lineNumber: 55; columnNumber: 17; 元素类型为 "configuration" 的内容必须匹配 "(properties?,settings?,typeAliases?,....
    	按照报错提示的顺序修改即可。
     -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    
  3. 通过一行代码设置分页数据(当前页,每页记录数)即可

    // 一定要在调用查询方法之前设置,否则无效
    // pageNum  就是要查询的真实的页数
    // pageSize 当前页显示的记录数
    PageHelper.startPage(pageNum,pageSize);
    
    //5.调用实现类的方法,接收结果
    List<Student> list = mapper.selectAll();
    
  4. 获取分页相关的其他数据

    // Page对象封装的内容和PageInfo一致
    // 两者的区别:page本质上是一个ArrayList集合,pageInfo是一个JavaBean
    //          之后在做JSON格式转换的时候会有区别,其他情况下基本一样。
    Page<Object> pageBean = PageHelper.startPage(3, 3);
    
    
    //5.调用实现类的方法,接收结果
    List<Student> list = mapper.selectAll();
    
    //6.处理结果
    for (Student student : list) {
        System.out.println(student);
    }
    
    //1. 获取分页相关参数方式1
    // PageInfo本质上就是一个封装了分页数据的JavaBean(Java实体类)
    PageInfo<Student> info = new PageInfo<>(list);
    System.out.println("总条数:" + info.getTotal());
    System.out.println("总页数:" + info.getPages());
    System.out.println("当前页:" + info.getPageNum());
    System.out.println("每页显示条数:" + info.getPageSize());
    System.out.println("上一页:" + info.getPrePage());
    System.out.println("下一页:" + info.getNextPage());
    System.out.println("是否是第一页:" + info.isIsFirstPage());
    System.out.println("是否是最后一页:" + info.isIsLastPage());
    
  5. page对象

    // Page对象封装的内容和PageInfo一致
    // 两者的区别:page本质上是一个ArrayList集合,pageInfo是一个JavaBean
    //          之后在做JSON格式转换的时候会有区别,其他情况下基本一样。
    Page<Object> pageBean = PageHelper.startPage(3, 3);
    
    
    //5.调用实现类的方法,接收结果
    List<Student> list = mapper.selectAll();
    
    //6.处理结果
    for (Student student : list) {
        System.out.println(student);
    }
    

2.4 注意事项

  1. 设置分页信息是在查询方法之前

  2. 获取并使用分页信息是在查询之后。

3. 多表关系

3.1 数据库中维护多表关系

  • 一对一

    建表原则:在任意一方添加一个外键列指向另一方的主键,外键唯一

  • 一对多

    建表原则:在多的一方添加一个外键指向一的一方的主键

  • 多对多

    建表原则:新建一个中间表,最少含有两个字段,分别作为外键指向另外两张表的主键

    本质上是多个一对多

  • 本质:通过**外键**来维护多表关系的

3.2 Java中维护多类关系

  • 一对一

    在任意一方添加一个属性(成员变量),类型为另外一方的类型

    Student{
        int id;
        String name;
        IdCard idCard; //这个人持有的身份证
    }
    IdCard{
        int id;
        String desc;
    }
    
  • 一对多

    在一的一方添加一个多的的一方的集合引用

    Classes{
       List<Student> stus; // 该班的所有学生
    }
    Student{
        
    }
    
  • 多对多

    拆分成多个一对多

    // 下面两种方式任选其一即可。
    Course{
        List<Student> stus; // 选本课的所有学生
    }
    student{
       List<Course> cours ; // 这个学生选的多门课程
    }
    
  • 本质:通过在**本类中持有一个其他的类的引用**来维护多个类之间的关系

3.3 一对一

建表语句

CREATE DATABASE web18_mybatis02;

USE web18_mybatis02;

CREATE TABLE person(
	id INT PRIMARY KEY AUTO_INCREMENT,
	`name` VARCHAR(20),
	age INT
);
INSERT INTO person VALUES (NULL,'张三',23);
INSERT INTO person VALUES (NULL,'李四',24);
INSERT INTO person VALUES (NULL,'王五',25);

CREATE TABLE card(
	id INT PRIMARY KEY AUTO_INCREMENT,
	number VARCHAR(30),
	pid INT,
	CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
);
INSERT INTO card VALUES (NULL,'12345',1);
INSERT INTO card VALUES (NULL,'23456',2);
INSERT INTO card VALUES (NULL,'34567',3);

在这里插入图片描述

实体类

public class Person {
    private Integer id;     //主键id
    private String name;    //人的姓名
    private Integer age;    //人的年龄

    // getter & setter ....
}
public class Card {
    private Integer id;     //主键id
    private String number;  //身份证号

    private Person p;       //所属人的对象
      // getter & setter ....
}  

映射配置文件

<!--配置字段和实体对象属性的映射关系-->
<!--
    resultMap 建立映射关系 :结果集字段名和实体属性名 两者映射关系
    type:查询的主类型 Card类型(内含一个Person类型的引用)

-->
<resultMap id="oneToOne" type="card">
    <!--
        id 主键列映射
            column 结果集字段名
            property javaBean的属性名
    -->
    <id column="cid" property="id" />
    <!--
        result 其他列映射
            column 结果集字段名
            property javaBean的属性名
     -->
    <result column="number" property="number" />
    <!--
        association:一对一类关系中,配置被包含类型的引用 person
        property:被包含对象的变量名
        javaType:被包含对象的数据类型
    -->
    <association property="p" javaType="person">
        <!-- id & result 和上面一样 -->
        <id column="pid" property="id" />
        <result column="name" property="name" />
        <result column="age" property="age" />
    </association>
</resultMap>

<!--
    resultMap作用:解决结果集字段名和实体属性名不一致时自动封装失败的问题
    其值为一个resultMap标签的id
 -->
<select id="selectAll" resultMap="oneToOne">
    SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
</select>

在这里插入图片描述

接口

public interface OneToOneMapper {
    //查询全部
    public abstract List<Card> selectAll();
}

测试类

//5.调用实现类的方法,接收结果
List<Card> list = mapper.selectAll();

//6.处理结果
for (Card c : list) {
    System.out.println(c);
}

3.4 一对多(本质)

建表语句

CREATE TABLE classes(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO classes VALUES (NULL,'黑马一班');
INSERT INTO classes VALUES (NULL,'黑马二班');


CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(30),
	age INT,
	cid INT,
	CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
);
INSERT INTO student VALUES (NULL,'张三',23,1);
INSERT INTO student VALUES (NULL,'李四',24,1);
INSERT INTO student VALUES (NULL,'王五',25,2);
INSERT INTO student VALUES (NULL,'赵六',26,2);

在这里插入图片描述

实体类

public class Student {
    private Integer id;     //主键id
    private String name;    //学生姓名
    private Integer age;    //学生年龄

    // getter & setter ....
}
public class Classes {
    private Integer id;     //主键id
    private String name;    //班级名称

    private List<Student> students; //班级中所有学生对象
    // getter & setter ....
}

映射配置文件

<!--
    resultMap 建立映射关系 :结果集字段名和实体属性名 两者映射关系
    type:查询的主类型 classes类型(内含一个Student类型的引用集合 students)

-->
<resultMap id="oneToMany" type="classes">
    <!-- id 主键列映射
        column 结果集字段名
        property javaBean的属性名

    -->
    <id column="cid" property="id"/>

    <!-- result 其他列映射
            column 结果集字段名
            property javaBean的属性名
     -->
    <result column="cname" property="name"/>

    <!--
        collection:一对多类关系中,配置被包含类型的引用的集合 students
        property:被包含对象集合的变量名 students
        ofType:集合中元素的数据类型 student
    -->
    <collection property="students" ofType="student">
        <id column="sid" property="id"/>
        <result column="sname" property="name"/>
        <result column="sage" property="age"/>
    </collection>
</resultMap>
<!--
    resultMap作用:解决结果集字段名和实体属性名不一致时自动封装失败的问题
        其值为一个resultMap标签的id
 -->
<select id="selectAll" resultMap="oneToMany">
    SELECT c.id cid,c.name cname,s.id sid,s.name sname,s.age sage FROM classes c,student s WHERE c.id=s.cid
</select>

[

接口

public interface OneToManyMapper {
    //查询全部
    public abstract List<Classes> selectAll();
}

测试类

//5.调用实现类的方法,接收结果
List<Classes> classes = mapper.selectAll();

//6.处理结果
for (Classes cls : classes) {
    System.out.println(cls.getId() + "," + cls.getName());
    List<Student> students = cls.getStudents();
    for (Student student : students) {
        System.out.println("\t" + student);
    }
}

//7.释放资源
sqlSession.close();
is.close();

3.5 多对多

建表语句

CREATE TABLE course(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO course VALUES (NULL,'语文');
INSERT INTO course VALUES (NULL,'数学');


CREATE TABLE stu_cr(
	id INT PRIMARY KEY AUTO_INCREMENT,
	sid INT,
	cid INT,
	CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
	CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);
INSERT INTO stu_cr VALUES (NULL,1,1);
INSERT INTO stu_cr VALUES (NULL,1,2);
INSERT INTO stu_cr VALUES (NULL,2,1);
INSERT INTO stu_cr VALUES (NULL,2,2);

在这里插入图片描述

实体类

Student{
    Integer id;
    String name;
    
    List<Course> courses;  // 一个学生对应多个课程,一对多
}

Course{
    Integer id;
    String name;
    
    List<Student> stus;    // 一个课程对应多个学生,一对多
}
// getter & setter ....

相当于多个一对多。

不同之处:多表联查时查询三张表

4. 延迟加载(理解)

4.1 概念

分步查询,延迟加载。

  • 概念:使用不到某个数据(对象)的时候,该数据(对象)就不需要存在;当使用时才获取或者创建。

  • 数据库中懒加载的样子(多表查询):

    在查询A、B两个表的时候,如果一开始只需要A表的数据,不需要看B表的数据,只查询A表数据;

    当用到B表数据的时候再发起新的SQL查询。

    -- 一开始只需要A表的数据
    select * from A
    
    -- 需要看B表的数据的时候,再去查询B表
    select * from B where id = A表中查询数来的B表的外键值
    

4.2 要求:

  1. 存在多表查询

    单表查询时只有一张表,无法先查A表,再查B表

  2. 不能使用多表联查

    多表联合查询时不能实现懒加载,或者说根本不涉及懒加载

    select * from A,B where a.bid = b.id
    
  3. 被关联的对象不会被立即使用

    如果立即使用,就不需要分步查询延迟加载了。

4.4 延迟加载的实现步骤

  • Mybatis核心配置文件settings中开启全局懒加载开关
    lazyLoadingEnabled=true
  • MybatisCardDao映射文件中使用新的方式配置resultMap
    • 编写查询所有card的statement
    • SQL语句为只查询所有身份证的SQL,返回值还是选择resultMap,指向一个resultMap
      • resultMap中Card的本身属性和字段映射关系不变
      • Card中关联用户的属性:在resultMapcollection子标签中添加两个属性
      • select属性,值为根据Card的id查询属于该Card的用户statement
    • column属性,值为select属性查询时需要传递的参数
  • 测试

4.5 相关设置参数

参数名表示意义默认值
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。false
aggressiveLazyLoadingfalse:每个属性会按需加载
true:当前对象任何方法执行都会立即加载该对象的所有属性
false (true in ≤3.4.1)
lazyLoadTriggerMethods指定当前对象的哪些方法执行的时候,会触发查询延迟加载的内容,而无论是否使用到了延迟加载的内容equals,clone,hashCode,toString

4.6 懒加载:一对一

CardDao.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="com.itheima.dao.CardDao">
    <!--
        多表联查,会一次性查出两张表有关的所有的数据
		分步查询延迟加载,可以分多次查询

        延迟加载
            分步查询,延迟加载
            先查询Card表,使用card中提供的数据;当使用到person的数据的时候,再去查询person

        要求:
            1. 存在多表查询
            2. 不能使用多表联查
            3. 在Mybatis的设置中开启延迟查询 lazyLoadingEnabled = true

        card对象中持有了一个person对象,person就是关联对象,如果开启了延迟查询,所有被关联对象都会延迟查询并加载。
            lazyLoadingEnabled  延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。


     -->
    <resultMap id="baseCard" type="com.itheima.domain.Card">
        <id column="id" property="id"/>
        <result column="number" property="number"/>

        <!--
            使用多表联查的时候,可以这样写
            <association property="" javaType="">
                <id></id>
                <result></result>
            </association>

            如果使用的延迟加载,格式如下:
         -->
        <!--
            association中
                select属性的含义:
                    表示要找哪个namespace下面的哪个statement去查询用户信息
                    要找哪个接口下面的哪个方法区查询person信息

                column 表示调用select中指定的方法时要传递的参数,
                    该参数源自于当前resultMap中的某一列的某个值
        -->

        <association
                property="p"
                javaType="com.itheima.domain.Person"
                select="com.itheima.dao.PersonDao.findById"
                column="pid"
        />

    </resultMap>

    <!--
        查询所有card,并延迟查询对应的person
     -->
    <!--
        这里面写的是resultType,满足结果集封装的要求,但是之后想要查询person就没办法进行了、。
        因为现在做的本质上还是多表查询,而非单表查询。
    <select id="findAll" resultType="com.itheima.domain.Card">-->


    <select id="findAll" resultMap="baseCard">
        select * from  card
    </select>

</mapper>

CardDao.java

package com.itheima.dao;
import com.itheima.bean.Card;
import java.util.List;

public interface CardDao {
    List<Card> findAll();
}

PersonDao.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="com.itheima.dao.PersonDao">


    <select id="findById" resultType="com.itheima.domain.Person">
        select * from  person where id = #{id}
    </select>
</mapper>

PersonDao.java

public interface PersonDao {

    Person findById(Integer id);
}

Test.java

package com.itheima.test;

import com.itheima.dao.CardDao;
import com.itheima.domain.Card;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @Author Vsunks.v
 * @Date 2020/12/5 16:49
 * @Blog blog.sunxiaowei.net
 * @Description:
 */
public class CardDaoLazyTest {

    SqlSession sqlSession = null;
    CardDao cardDao = null;

    @Before
    public void before() throws IOException {
        // 加载配置文件
        String resouce = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(resouce);

        // 构建SQLSession工厂
        SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);

        // 获取SQLSession对象
        sqlSession = ssf.openSession(true);

        // 获取代理对象
        cardDao = sqlSession.getMapper(CardDao.class);
    }

    //需求1:   查询所有card,并延迟查询对应的person
    @Test
    public void test01() {

        List<Card> cards = cardDao.findAll();

        // 没有用到用户信息
        System.out.println("cards.get(0).getNumber() = " + cards.get(0).getNumber());

        System.out.println("******************************************");

        // 使用到用户信息
        System.out.println("cards.get(0).getP() = " + cards.get(0).getP());
        System.out.println("******************************************");

        // 使用所有用户的信息
        System.out.println("cards = " + cards);
    }

    @After
    public void after() {
        sqlSession.close();
    }
}

4.7 懒加载:一对多

ClassesDao.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="com.itheima.dao.ClassesDao">


    <resultMap id="baseClasses" type="com.itheima.bean.Classes">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>

        <!--
            select 查询被关联对象的statement
            column 本resultMap对应的结果集中,作为查询条件的某一列列名
        -->


        <collection property="students"
                    ofType="com.itheima.bean.Student"
                    select="com.itheima.dao.StudentDao.findByClassId"
                    column="id" />
    </resultMap>

    <select id="findById" resultMap="baseClasses">
        select * from  classes where id = #{id}
    </select>
</mapper>

ClassesDao.java

public interface ClassesDao {
    Classes findById(Integer id);
}

PersonDao.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="com.itheima.dao.StudentDao">


    <select id="findByClassId" resultType="com.itheima.bean.Student">
        select * from student where cid = #{id}
    </select>
</mapper>

PersonDao.java

public interface StudentDao {
    List<Student> findByClassId(Integer cid);
}

Test.java

public static void main(String[] args) throws IOException {
    //1.加载核心配置文件
    InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

    //2.获取SqlSession工厂对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

    //3.通过工厂对象获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession(true);

    //4.获取OneToOneMapper接口的实现类对象
    ClassesDao mapper = sqlSession.getMapper(ClassesDao.class);

    //5.调用实现类的方法,接收结果
    Classes classes = mapper.findById(1);

    // 只使用classes数据
    System.out.println("classes.getName() = " + classes.getName());

    //使用classes对应的student信息
    System.out.println("classes.getStudents() = " + classes.getStudents());

    //6.处理结果

}

4.8 图解

在这里插入图片描述

4.9 注意点

使用XML和注解都两种配置都可以实现分步查询,延迟加载。

思路是一样,不一样的是配置方式。

4.10 延迟加载和非延迟加载的区别

  1. 延迟加载需要发送1+nSQL
  2. 多表联查的非延迟加载,发送1条SQL

4.11 延迟查询策略在工作中用法

  • 是否使用

    如果所有数据要求一次查询出来,就不需要分步查询,延迟加载;否则,可以使用

  • 查询多的一方(学生)的时候,不需要分步 查询,延迟加载

    • 通常需要关联查询一的一方(班级)
  • 查询一的一方(班级)的时候,需要分步查询,延迟加载

    • 通常不会关联查询多的一方(学生)
    • 根据业务,在需要展示 多 学生 的时候才去查询
  • 上面的思路仅仅是建议思路,具体实现看甲方需求。

  • 延迟加载思想

    • 首先查询主要内容,后面根据业务需要是否查询关联内容
  • 注意点

    • 只要是多表查询,都可以使用懒加载。包含一对一、一对多和多对多
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值