Mybatis的高级映射及延迟加载

高级映射
  • 之前我们使用mybatis时,都是单表映射——一张数据库表对应一个java类。但在实际应用中,往往有多张表,且这些表之间是存在某种关系的比如:一对一、一对多、多对一等,针对以上情况,mybatis中提供了高级映射机制,来解决数据库表与java对象之间的映射关系。

  • 以下以班级表和学生表为例

  • 有两种解决方案:

    1. 将表的关系看作是多对一,即多个学生对应一个班级。以多的一方(Student)作为主表,Student对象作为主对象,Clazz对象作为副对象。通过Student对象可以找到对应的Clazz对象,因此在Student中添加一个Clazz属性。

      • mybatis中实现多对一映射的方法

        1. 一条sql语句,级联属性的方法

          •     <resultMap id="studentResultMap" type="student">
                    <id property="id" column="id"></id>
                    <result property="name" column="name"></result>
                    <result property="clazz.cid" column="cid"></result>
                    <result property="clazz.cname" column="cname"></result>
                </resultMap>
                <select id="selectById" resultMap="studentResultMap">
                    select
                    s.id,s.name,c.cid,c.cname
                    from t_stud s left join t_clazz c on s.cid = c.cid
                    where s.id = #{id}
                </select>
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21

            2. 一条sql语句,采用association标签进行表的关联。

            * ```xml
            <resultMap id="studentResultMap2" type="student">
            <id property="id" column="id"></id>
            <result property="name" column="name"></result>
            <!-- property: 需要关联的pojo类的属性,在本例中就是Student类的clazz属性-->
            <!-- javaType:需要关联的Java类,在本例中就是Clazz类,这里使用了别名-->
            <association property="clazz" javaType="Clazz">
            <id property="cid" column="cid"></id>
            <result property="cname" column="cname"></result>
            </association>
            </resultMap>
            <select id="selectById2" resultMap="studentResultMap2">
            select
            s.id,s.name,c.cid,c.cname
            from
            t_stud s left join t_clazz c on s.cid = c.cid
            where s.id = #{id}
            </select>
        2. 前两种方法都是通过一条sql语句进行多表查询的方式,接下来这种方法是通过两条sql语句进行分步查询。即先根据id获取student,再通过student获得clazz对象。

          •     <!--StudentMapper.xml-->
            <resultMap id="StudentResultMapStep" type="student">
                    <id property="id" column="id"></id>
                    <result property="name" column="name"></result>
                    <association property="clazz"
                                 select="com.deng.mybatis.mapper.ClazzMapper.selectByCidStep2"
                                 column="cid"></association>
                </resultMap>
                <select id="selectByIdStep1" resultMap="StudentResultMapStep">
                    select id,name,cid from t_stud where id = #{id}
                </select>
            
            1
            2
            3
            4
            5
            6
                   
            * ```xml
            <!--ClazzMapper.xml-->
            <select id="selectByCidStep2" resultType="clazz">
            select cid,cname from t_clazz where cid = #{cid}
            </select>
          • 这种做法的好处在于,代码可复用以及支持延迟加载(懒加载)

          • 因为拆解成了两步,每一步都可以被复用

          • 支持延迟加载:在使用的时候执行查询语句,不使用的时候不执行查询语句。可以提高性能。

          • 比如:如果我只需要查询student的name,通过前两种方式会将两个表进行匹配,查询时间是n*m的。而如果使用第三种方式并且开启延迟加载,那么就只会执行一条sql语句,查询时间为n。

          • Preparing: select id,name,cid from t_stud where id = ?
            
            1
            2
            3
            4
            5
                   
            * 可以在mybatis核心配置文件中的settings标签添加以下代码,开启全局延迟加载,使用后只要是分步查询都会开启延迟加载功能

            * ```xml
            <setting name="lazyLoadingEnabled" value="true"></setting>
          • 可以在association标签中通过设置fetchType = eager来局部关闭延迟加载

    2. 就是将表之间的关系看成是一对多,在本例中就是指一个班级对应多个学生。在这种关系下,我们需要将班级表作为主表,班级对象作为主对象。实现的原理就是,先查询某个班级,再通过该班级查询学生。因此需要在Clazz类中添加一个Student集合属性,用来存放查询到的学生。

      • mybatis中实现一对多关系间的映射的方法

        1. collection标签(类似一对多中的association标签),一条sql语句。通过多表连接查询

          •     <resultMap id="selectByCollectionMap" type="Clazz">
                    <id property="cid" column="cid"></id>
                    <result property="cname" column="cname"></result>
                    <!--        property: 需要关联的pojo类的属性,在本例中就是Clazz类的studs属性-->
            <!--        ofType:需要关联的Java类,在本例中就是Student类,这里使用了别名-->
                    <collection property="studs" ofType="student">
                        <id property="id" column="id"></id>
                        <result property="name" column="name"></result>
                    </collection>
                </resultMap>
            
                <select id="selectByCollection" resultMap="selectByCollectionMap">
                    select
                    c.cid,c.cname,s.id,s.name
                    from
                    t_clazz c left join t_stud s on c.cid = s.cid
                    where c.cid = #{cid}
                </select>
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
              
            *

            2. 分步查询.两条sql语句,先根据cid查询clazz对象,再通过cid查询student对象。有同学可能会问,为啥不直接根据cid查询student,那是因为这样做无法查出班级名称。

            * ```xml
            <!--ClazzMapper.xml-->
            <resultMap id="selectByCidStep1" type="clazz">
            <id property="cid" column="cid"></id>
            <result property="cname" column="cname"></result>
            <collection property="studs"
            select="com.deng.mybatis.mapper.StudentMapper.selectByCidStep2"
            column="cid"></collection>
            </resultMap>

            <select id="selectByCidStep1" resultMap="selectByCidStep1">
            select cid,cname from t_clazz where cid = #{cid}
            </select>
          • <!--StudentMapper.xml-->
             <select id="selectByCidStep2" resultType="student">
                    select id,name from t_stud where cid = #{cid}
                </select>