zoukankan      html  css  js  c++  java
  • 【Mybatis】08 ResultMap、Association、分步查询、懒加载

    ResultMap自定义结果集

    可以把查询返回的结果集封装成复杂的JavaBean对象

    原来的ResultType属性,只能把查询到的结果集转换为简单的JavaBean

    什么是简单的JavaBean对象?

    - 不具有JavaBean和集合类型属性的对象

    - 也就是不能建立ORM的多表关联映射

    问题的引入:

    如果字段标识符和数据表不一致,

    例如实体类的user的密码字段,现在更改为pwd

    数据表的字段依然为user_password

    我们查询这个结果看看

    所有的密码字段接受失败

    那么,该如何解决这个问题?

    方案一,在SQL语句中给这个字段起别名

    再次测试,这个数据又能获取到了

    但是这样的解决方案并不优雅

    Mybatis提供了一个解决方案,使用ResultMap对字段标识进行映射绑定

    测试结果,可行

    一对一关系案例:

    创建数据表

    锁表 & 钥匙【一把锁就配一把钥匙】

    CREATE TABLE t_lock(
        `id` INT PRIMARY KEY AUTO_INCREMENT,
        `name` VARCHAR(50)
    
    );
    
    CREATE TABLE t_key(
        `id` INT PRIMARY KEY AUTO_INCREMENT,
        `name` VARCHAR(50),
        `lock_id` INT,
        FOREIGN KEY(`lock_id`) REFERENCES t_lock(`id`)
    );

    添加数据

    INSERT INTO t_lock(`name`) 
    VALUES
        ('阿里巴巴'),
        ('联想'),
        ('华为');
        
    INSERT INTO t_key(`name`,`lock_id`) 
    VALUES
        ('马云',1),
        ('任正非',2),
        ('柳传志',3);

    【写反了,唉就这样把】

    创建ORM实体类

    锁类

    package cn.dai.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author ArkD42
     * @file Mybatis
     * @create 2020 - 05 - 29 - 13:30
     */
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Lock {
    
        private Integer id;
        private String name;
    }

    钥匙类

    package cn.dai.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author ArkD42
     * @file Mybatis
     * @create 2020 - 05 - 29 - 13:32
     */
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Key {
    
        private Integer id;
        private String name;
    
        // 注意这个设置的外键是来自这个锁对象的属性
        private Lock lock;
    
    }

    映射器【KeyMaper.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接口名称-->
    <mapper namespace="cn.dai.mapper.KeyMapper">
    
        <select id="queryKeyById" resultType="cn.dai.pojo.Key" parameterType="java.lang.Integer">
            SELECT * FROM t_key WHERE id = #{id}
        </select>
    
    </mapper>

    注意!在这里采用的结果集类型,先看看结果如何

    测试类

        @Test
        public void sqlTest6(){
            logger.info("- - - - TESTING - - - -");
            SqlSession sqlSession = MybatisUtil.getSqlSession(true);
            KeyMapper keyMapper = sqlSession.getMapper(KeyMapper.class);
    
            Key key = keyMapper.queryKeyById(2);
            System.out.println(key);
    
            sqlSession.close();
        }

    结果:我们对应的锁类无法获取

    我们需要一个关联查询来实现

    首先从SQL语句实现

    【查询钥匙表关联锁表,一起获取】

            SELECT
                t_key.*,t_lock.name lock_name
            FROM
                t_key LEFT JOIN t_lock
            ON
                t_key.lock_id = t_lock.id
            WHERE
                t_key.id = #{id}

    【就算是这样,没有类型匹配,返回的结果还是和上面一样,这里不展示了】

    【留意SELECT子句筛选的字段】

    所以需要通过结果集映射标签实现一些类型的绑定

    使用默认的result标签处理

    然后使用我们的结果集映射标签实现关联处理

    <?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接口名称-->
    <mapper namespace="cn.dai.mapper.KeyMapper">
    
        <!--
            id 设置这个结果集映射标签的标识,
            type 设置需要转换出来的实体类对象的全限定类名
        -->
        <resultMap id="key" type="key">
    
            <!-- id标签负责 转换主键列 -> 实体类的属性 -->
            <id column="id" property="id"/>
            <!-- 非主键列 转换给 实体类属性 -->
            <result column="name" property="name"/>
            <!-- 一般匹配的字段不需要显示的写出来,因为是默认的了 -->
    
    
            <!--
                property 对应的是实体类的属性
                column 对应的是数据表的列
            -->
            <result column="lock_id" property="lock.id" />
            <result column="lock_name" property="lock.name" />
    
        </resultMap>
    
        <!-- 这里的结果集映射就对应上面设置的id -->
        <select id="queryKeyById" resultMap="key" parameterType="int">
            SELECT
                t_key.*,t_lock.name lock_name
            FROM
                t_key LEFT JOIN t_lock
            ON
                t_key.lock_id = t_lock.id
            WHERE
                t_key.id = #{id}
        </select>
    
    </mapper>

    测试结果

    千万要注意,要实现这个锁的名称的输出,就要留意上面的SELECT 筛选的字段

    可以通过别名映射实现一些实体类的绑定

    在这里是因为左外链接,所以可以看到,钥匙表是没有写这个表名的

     或者使用Association标签实现映射

     在结果集中设置关联映射标签,绑定属性标识和所对应的类型

    其次声明关联表的属性映射

           <association property="lock" javaType="cn.dai.pojo.Lock">
               <id column="lock_id" property="id"/>
               <result column="lock_name" property="name" />
           </association>

    Association定义分布查询

    什么意思?

    可以通过一个查询得到子对象

    分两种加载,立即加载和懒加载

    一张表可能存在50多列,其中主要常用的是最前面的6列

    后面的44列不一定马上需要,所以我们的查询应该拆分成两次查询

    我们声明一个两步查询的方法

    Key queryKeyByIdForTwoStep(Integer id);

    对副表的二次查询在锁表中编写

    package cn.dai.mapper;
    
    import cn.dai.pojo.Lock;
    
    /**
     * @author ArkD42
     * @file Mybatis
     * @create 2020 - 05 - 30 - 11:59
     */
    public interface LockMapper {
        
        Lock queryLockById(Integer id);
        
    }

    锁表的映射器

    <?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接口名称-->
    <mapper namespace="cn.dai.mapper.LockMapper">
        
        <select id="queryLockById" resultType="cn.dai.pojo.Lock" >
            select * from t_lock where id = #{id}
        </select>
    
    </mapper>

    钥匙表的映射器

        <resultMap id="key2" type="cn.dai.pojo.Key">
    
            <id column="id" property="id"/>
            <result column="name" property="name"/>
            
            <!-- 
                select 调用另外一个映射器的查询方法,来获取对象的结果
                column 把这钥匙表的查询SQL的字段结果返回给这个关联查询调用【就是那个查询的参数】
                
            -->
            <association 
                    property="lock" 
                    javaType="cn.dai.pojo.Lock" 
                    select="cn.dai.mapper.LockMapper.queryLockById"
                    column="lock_id"
            />
    
        </resultMap>
    
        <select id="queryKeyByIdForTwoStep" resultMap="key2" parameterType="int">
            SELECT
                id,name,lock_id
            FROM
                t_key
            WHERE
                t_key.id = #{id}
        </select>

    测试结果

    可以看到这样查询分了两次执行,并且把字段的参数传递给下一个查询的使用

    开启懒加载查询

    即延迟加载,减少非必要性的查询

    优化数据库性能,需要在全局配置中开启

            <!-- 开启懒加载 -->
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="aggressiveLazyLoading" value="false"/>

        @Test
        public void sqlTest7(){
            logger.info("- - - - TESTING - - - -");
            SqlSession sqlSession = MybatisUtil.getSqlSession(true);
            KeyMapper keyMapper = sqlSession.getMapper(KeyMapper.class);
    
            Key key = keyMapper.queryKeyByIdForTwoStep(2);
    
            //System.out.println(key);
    
            //开启懒加载是什么效果?如果我们不调用附表的信息,第二个查询是不会调用的
            System.out.println(key.getName());
    
            sqlSession.close();
        }

    结果

    实际作用远不止这些,详见官方文档:

    https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

  • 相关阅读:
    Python面向对象编程——什么是面向对象的程序设计
    Python面向对象编程——基本语法
    Python面向对象编程——简介
    Python函数编程——迭代器
    Python函数编程——列表生成式和生成器
    Python函数编程——闭包和装饰器
    Python函数编程——名称空间
    开始写游戏 --- 第二十七篇
    开始写游戏 --- 第二十六篇
    开始写游戏 --- 第二十五篇
  • 原文地址:https://www.cnblogs.com/mindzone/p/12825673.html
Copyright © 2011-2022 走看看