• Mybatis学习总结(八)——延迟加载


    一、什么是延迟加载

    resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

    需求:如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

    延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

     二、使用association实现延迟加载

    需要定义两个mapper的方法对应的statement。

    1、只查询订单信息

      SELECT * FROM orders

    在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)

    2、关联查询用户信息

      通过上边查询到的订单信息中user_id去关联查询用户信息

    OrdersCustomMapper.xml的延迟加载的核心代码:

      使用association中的select指定延迟加载去执行的statement的id。

    <!-- 查询订单关联查询用户,用户信息按需延迟加载 的 resultMap定义 -->
    <resultMap type="com.mybatis.entity.Orders" id="ordersUserLazyLoading">
         <!--对订单信息进行映射配置  -->
         <id column="id" property="id"/>
         <result column="number" property="number"/>
         <result column="createtime" property="createTime"/>
         <result column="note" property="note"/>
          <!-- 实现对用户信息进行延迟加载
             select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement) 
             column:订单信息中关联用户信息查询的列,是user_id
                                   关联查询的sql理解为:
              SELECT orders.*,
                 (SELECT username FROM USER WHERE orders.user_id = user.id)username,
                 (SELECT sex FROM USER WHERE orders.user_id = user.id)sex
              FROM orders
         -->
         <association property="user"  javaType="com.mybatis.entity.User" select="findUserById" column="user_id"/>
    </resultMap>
    
    <!-- 根据Id查询用户,用于测试延迟加载 -->
    <select id="findUserById" parameterType="int" resultType="com.mybatis.entity.User" >
        select * from t_user where id=#{id}
    </select>
    
    <!-- 查询订单关联用户,用户信息延迟加载 -->
    <select id="findOrdersUserLazyLoading" resultMap="ordersUserLazyLoading">
        select * from orders
    </select> 

    OrdersCustomMapper.java的代码:

    /**查询订单,关联查询用户,用户按需延迟加载*/
    public List<Orders>findOrdersUserLazyLoading();
    
    /**根据Id查询用户(这个方法本应该放在UserMapper类的,测试方便先放在这)*/
    public User findUserById(int id); 

    测试思路及代码:

    1、执行上边mapper方法(findOrdersUserLazyLoading),内部去调用OrdersMapperCustom中的findOrdersUserLazyLoading只查询orders信息(单表)。

    2、在程序中去遍历上一步骤查询出的List<Orders>,当我们调用Orders中的getUser方法时,开始进行延迟加载。

    3、延迟加载,去调用findUserbyId这个方法获取用户信息。

    // 查询用户关联查询用户,用户信息延迟加载
    @Test
    public void TestFindOrdersUserLazyLoading() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 创建代理对象
        OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
        // 调用mapper的方法
        List<Orders> list = oc.findOrdersUserLazyLoading();
        for(Orders order: list){
            //执行getUser()去查询用户信息,这里实现延迟加载
            User user = order.getUser();
            System.out.println(user);
        }
        sqlSession.close();
    }

    注:项目中要引入cglib.jar和asm.jar。

    三、延迟加载在mybatis核心配置文件sqlMapConfig.xml中的配置

    mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。

    在mybatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading

    设置项 描述 允许值 默认值
    lazyLoadingEnabled 全局性设置懒加载。如果设为'false',则所有相关联的都会被初始化加载。 true | false false
    aggressiveLazyLoading 当设置为'true'的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 true | false true
    <!-- 全局参数的配置 -->
    <settings>
        <!--打开延迟加载的开关  -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--将积极加载改为消极加载及按需加载  -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    四、延迟加载的原理

         它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

    小结:使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。

  • 相关阅读:
    codevs 1115 开心的金明
    POJ 1125 Stockbroker Grapevine
    POJ 2421 constructing roads
    codevs 1390 回文平方数 USACO
    codevs 1131 统计单词数 2011年NOIP全国联赛普及组
    codevs 1313 质因数分解
    洛谷 绕钉子的长绳子
    洛谷 P1276 校门外的树(增强版)
    codevs 2627 村村通
    codevs 1191 数轴染色
  • 原文地址:https://www.cnblogs.com/xiaoxi/p/6640045.html
Copyright © 2020-2023  润新知