MyBatis (五)—— 延迟加载

高级映射

在学习延迟加载之前,先来学习什么是高级映射吧;

高级映射其实就是数据库表与表之间的关系,那么具体的关系又可以分为三种(拿学生表和班级表做说明):

  1. 一对一关系;如学生之于班级
  2. 一对多关系;如班级至于学生
  3. 多对多关系;这个比如一个用户可以购买多个商品,而一个商品可以被多个用户购买,这样的用户表和商品表之间就是多对多关系;

一对一关联映射

使用到的两个表如下:
在这里插入图片描述
在这里插入图片描述

先创建两个bean类:

public class Student {
    private int Sid;
    private String Sname;
    private int Cid;

    //get、set和toString方法略
}
public class Classes {
    private int Cid;
    private String Cname;

    //get、set和toString方法略
}

两个对应的dao层接口:

public interface StudentDao {
    public StudentVo getById1(int id);
}
public interface ClassesDao {
    public Classes getById1(int id);
}
方式一:resultType

这个方法需要创建一个新类,因为返回的是一个新的对象,要拿一个新的类让mybatis完成映射:

public class StudentVo {
    private int Sid;
    private String Sname;
    private int Cid;
    private String Cname;

    //get、set和toString方法略
}

我是直接创建了一个新的类StudentVo,让后把对应的属性全部添加在里面,也可以通过继承Student、Classes两个类中的一个,再把缺的属性添加在这个新类里面就好,我这个例子里面属性比较少,就直接全写在里面了;

需要使用的StudentDao.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.tulun7.dao.StudentDao">
    <select id="getById1" parameterType="java.lang.Integer" resultType="com.tulun7.bean.StudentVo">
        select
            student1.Sid,
            student1.Sname,
            classes.Cid,
            classes.Cname
        from
            student1,classes
        where
            student1.Cid = classes.Cid
            and Student1.Sid = #{id}
    </select>
</mapper>

mybatis的全局配置文件mybatis.xml:

<?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>
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <!--数据源配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射-->
    <mappers>
        <mapper resource="延时加载/StudentDao.xml"/>
    </mappers>

</configuration>

测试:

public class TestDemo1 {
    @Test
    public void test() throws IOException {
        String resource = "延时加载/mybatis.xml";
        //读取配置文件
        InputStream asStream = Resources.getResourceAsStream(resource);
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);

        //创建sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过动态代理产生StudentMapper对象
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
        StudentVo byId1 = mapper.getById1(1901);
        System.out.println(byId1);
    }
}

在这里插入图片描述

方式二:resultMap

这种实现方法,需要把Classes当做Student类中的一个属性,即需要改变Student类(我直接写了一个新的类Student1):

public class Student1 {
    private int Sid;
    private String Sname;
    private int Cid;
    private Classes classes; //把关联的这儿当属性

    //get、set和toString方法略
}

在StudentDao接口里面添加一个方法:

public interface StudentDao {
    public StudentVo getById1(int id);
    public Student1 getById2(int id);  //添加新方法
}

那他的StudentDao1.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.tulun7.dao.StudentDao">
    <!-- 定义一个resultMap, 学生 > 班级 ,将查询的结果映射Student1-->
    <resultMap id="student1Map" type="com.tulun7.bean.Student1">
        <!-- 数据库表Student1对应 pojo中的Student1.java -->
        <!--  id:唯一标识
              result:普通标识
              column:数据库的字段
              property:对应bean类的属性-->
        <id column="Sid" property="Sid"/>
        <result column="Sname" property="Sname"/>
        <result column="Cid" property="Cid"/>
        <!-- 配置关联用户信息 -->
        <!-- association:用于映射关联查询单个对象的信息
              property:要将关联查询的班级信息映射到Student1中哪个属性
              javaType:映射到哪个类-->
        <association property="classes"  javaType="com.tulun7.bean.Classes">
            <id column="Cid" property="Cid"/>
            <result column="Cname" property="Cname"/>
        </association>
    </resultMap>

    <select id="getById2" resultMap="student1Map">
        select
            student1.Sid,
            student1.Sname,
            classes.Cid,
            classes.Cname
        from
            student1,classes
        where
            student1.Cid = classes.Cid
            and Student1.Sid = #{id}
    </select>
</mapper>

在mybatis的全局配置文件mybatis.xml里面添加映射文件StudentDao1.xml(略),测试:

public class TestDemo2 {
    @Test
    public void test() throws IOException {
        String resource = "延时加载/mybatis.xml";
        //读取配置文件
        InputStream asStream = Resources.getResourceAsStream(resource);
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);

        //创建sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过动态代理产生StudentMapper对象
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
        Student1 byId2 = mapper.getById2(1902);
        System.out.println(byId2);
    }
}

在这里插入图片描述
一对一的两种实现就完了,总结:

  • resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求建议使用resultType。
  • resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。

resultMap可以实现延迟加载,resultType无法实现延迟加载。

一对多关联映射

方式一:resultType

这个和上面一对一关联映射的resultType实现差不多,也需要一个新类,因为返回的是一个新对象,需要注意的是一对多的时候一个班级对应多个学生,所以返回的是集合,重要的点我截图如下,其他的我就略了:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方式二:resultMap

重点来说通过resultMap如何实现吧,因为一对多的关联映射的resultMap实现和一对一的resultMap实现不一样:

他需要在班级类里面添加学生的集合属性(创建了一个新的类Classes1):

public class Classes1 {
    private int Cid;
    private String Cname;
    private List<Student> list;

    //get、set和toString方法略
}

在ClassesDao接口里面添加方法:

public interface ClassesDao {
    public List<ClassesVo> getById1(int id);
    public Classes1 getById2(int id);  //添加方法
}

然后主要看的就是对应的ClassesDao1.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.tulun7.dao.ClassesDao">
    <resultMap id="classesMap" type="com.tulun7.bean.Classes1">
        <id column="Cid" property="Cid"/>
        <result column="Cname" property="Cname"/>

        <!-- 一对多采用collection集合映射
            collection: 将关联查询到的多条记录映射到对象集合中
            property: 对应类的属性
            ofType:指定映射的类 -->
        <collection property="list" ofType="com.tulun7.bean.Student">
            <id column="Sid" property="Sid"/>
            <result column="Sname" property="Sname"/>
            <result column="Cid" property="Cid"/>
        </collection>
    </resultMap>

    <select id="getById2" resultMap="classesMap">
        select
            classes.Cid,
            classes.Cname,
            student1.Sid,
            student1.Sname,
            student1.Cid
        from
            student1,classes
        where
            student1.Cid = classes.Cid
            and classes.Cid = #{id}
    </select>
</mapper>

改一下全局配置文件mybati.xml的映射文件的位置,测试:

public class TestDemo4 {
    @Test
    public void test() throws IOException {
        String resource = "延时加载/mybatis3.xml";
        //读取配置文件
        InputStream asStream = Resources.getResourceAsStream(resource);
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);

        //创建sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过动态代理产生StudentMapper对象
        ClassesDao mapper = sqlSession.getMapper(ClassesDao.class);
        Classes1 byId2 = mapper.getById2(1);
        System.out.println(byId2);
    }
}

在这里插入图片描述

多对多关联映射

这个给篇别人的博文的地址吧→https://blog.csdn.net/hefenglian/article/details/80699723

延迟加载

延迟加载或者也叫惰性加载,懒加载。使用延迟加载可以提高程序的运行效率。Java程序与数据库交互的频次越低,程序运行效率越高,所以我们应该尽量减少Java程序与数据库的交互次数,MyBatis延迟加载就很好的做到了这一点。

通过一个具体的业务场景来理解延迟加载:

班级(Classes)和学生(Student),当我们查询Student对象时,因为有级联关系,所以会将对应的Classes对象一并查询出来,这样就需要发送两条SQL语句,分别查询classes表和student表中的数据。

延迟加载的思路是:当我们查询Student的时候,如果没有调用classes属性,则只发送了一条SQL语句查询Student;如果需要调用classes属性,则发送两条SQL语句查询Student和Classes。所以延迟加载可以看做是一种优化机制,根据具体的代码,自动选择发送的SQL语句条数。

如果不使用延迟加载:

先创建两个bean类:

public class Student1 {
    private int Sid;
    private String Sname;
    private int Cid;
    private Classes classes; //把关联的这儿当属性
    
    //get、set和toString方法略
}
public class Classes {
    private int Cid;
    private String Cname;

    //get、set和toString方法略
}

两个对应的dao层接口:

public interface StudentDao {
    public Student1 getById2(int id);
}
public interface ClassesDao {
    public Classes getById3(int id);
}

当我们不使用延迟加载的时候,那么对应的ClassesDao2.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.tulun7.dao.ClassesDao">
    <select id="getById3" parameterType="java.lang.Integer" resultType="com.tulun7.bean.Classes">
        select * from classes where classes.Cid = #{id}
    </select>
</mapper>

对应的StudentDao2.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.tulun7.dao.StudentDao">
    <resultMap id="student1Map" type="com.tulun7.bean.Student1">
        <id column="Sid" property="Sid"/>
        <result column="Sname" property="Sname"/>
        <result column="Cid" property="Cid"/>
        <!--需要使用select属性 后面跟对应接口的全路径名加对应的方法名-->
        <association column="Cid" property="classes"  javaType="com.tulun7.bean.Classes"
                     select="com.tulun7.dao.ClassesDao.getById3">
        </association>
    </resultMap>

    <select id="getById2" resultMap="student1Map">
        select * from student1 where Student1.Sid = #{id}
    </select>
</mapper>

全局配置文件如下mybatis4.xml:

<?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>
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="LOG4J"></setting>
        
    </settings>

    <!--数据源配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射-->
    <mappers>
        <mapper resource="延时加载/ClassesDao2.xml"/>
        <mapper resource="延时加载/StudentDao2.xml"/>
    </mappers>

</configuration>

测试代码:

public class TestDemo5 {
    @Test
    public void test() throws IOException {
        String resource = "延时加载/mybatis4.xml";
        //读取配置文件
        InputStream asStream = Resources.getResourceAsStream(resource);
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);

        //创建sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过动态代理产生StudentMapper对象
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
        Student1 byId2 = mapper.getById2(1901);
        System.out.println(byId2.getSname());
    }
}

在这里插入图片描述
结果如图所示,我查询了一个学生表并且只需要一个学生姓名即可,而实际却有两条sql,分别查询了学生表、班级表,当前我在查询的时候,查询是学生表,可以看作我并不需要班级表的信息,而它这样的加载方式也叫积极加载,即把关联的表信息也查询一次,不管你需不需要,这样就会存在一定的效率问题,所以我们引进了延迟加载这种加载方式,也即按需加载;

如果使用延迟加载:

在上面的全局配置文件里面打开延迟加载开关、开启按需加载即可:

<?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>
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="LOG4J"></setting>
        <!--================================================-->
        <!-- 打开延迟加载的开关 -->
        <setting name="lazyLoadingEnabled" value="true" />
        <!-- 将即时加载改为按需加载 他默认的是积极加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--================================================-->
    </settings>

    <!--数据源配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射-->
    <mappers>
        <mapper resource="延时加载/ClassesDao2.xml"/>
        <mapper resource="延时加载/StudentDao2.xml"/>
    </mappers>

</configuration>

再次测试(测试代码同上):
在这里插入图片描述
它就只有一条sql语句了,而当我们需要查询班级信息时,它会按需加载:

public class TestDemo7 {
    @Test
    public void test() throws IOException {
        String resource = "延时加载/mybatis5.xml";
        //读取配置文件
        InputStream asStream = Resources.getResourceAsStream(resource);
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);

        //创建sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过动态代理产生StudentMapper对象
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
        Student1 byId2 = mapper.getById2(1901);
        System.out.println(byId2.getClasses());
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值