【Mybatis】04 - Mybatis延迟加载与缓存

1. Mybatis中的延迟加载

1.1 问题

  1. 在一对多中,当一个用户有一百个账户,在查询用户的时候,要不要把关联的账户查询出来?在查询账户的时候,要不要将关联的用户查询出来?

1.2 解决

1 在查询用户时,用户下的账户信息应该是什么时候使用,什么时候查询的。(延迟加载)

  1. 在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。(立即加载)

1.3 概念

  1. 延迟加载 :在真正使用数据时才发起查询, 不用的时候不查询。也叫按需加载或懒加载。

  2. 立即加载:不管用不用,只要一旦调用方法,马上发起查询。

1.4 对应的四种表关系

  1. 一对多 ||多对多 :通常使用的是延迟加载;

  2. 多对一 || 一对一:通常使用的是立即加载;

2. 一对一实现延迟加载

2.1 创建一个新Demo

  1. 这里的Demo不使用骨架的方式创建,之后复制之前一对多Demo的代码。进行测试。

  2. 在查询账户的时查询用户信息,修改AccountDao.xml

<resultMap id="accountUserMap" type="account">
        <!--此处使用懒加载数据库字段名称修改回来了 所以这里column = "id"-->
        <id property="id" column="id"/>
        <result property="uid" column="uid"/>
        <result property="money" column="money"/>
        <!--
        一对一的关系映射:配置封装user的内容
            property : 实体类中的类名
            column : 关联的字段
            javaType : 封装的类型
            select : 指定需要查询的方法全限定类名 + 方法名称
        -->
        <association property="user" column="uid" javaType="user" select="com.lyp.dao.UserDao.findById">
        </association>
    </resultMap>
  <!--使用关联查询-->
    <select id="findAll" resultMap="accountUserMap">
       select *

       from account
    </select>
  1. 在全局配置文件中配置懒加载:参考网址
配置延迟加载
使用settings标签机进行配置
 <!--配置延迟加载-->
    <settings>
        <!--延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
注意事项这里的配置标签是有顺序的一定需要按照规定的顺序进行配置,否则将报错。
配置的标签顺序
  1. 配置延迟加载之前 控制台日志信息:
配置懒加载之前的查询
配置懒加载之后的查询

3. 一对多实现延迟加载

  1. 在AccountDao.java持久层接口中添加根据用户id查询账户信息的方法。并在AccountDao.xml配置文件中进行配置:
    /**
     * 根据用户id查询账户信息
     * @param uid
     * @return
     */
    List<Account> findAccountByUid(Integer uid);
 <!--根据用户id查询账户户信息-->
    <select id="findAccountByUid" resultType="account" parameterType="int">
        select * from account  where uid = #{uid}
    </select>
  1. 在UserDao.xml中修改,用户和账户的关联映射:
 <resultMap id="userAccountMap" type="user">
        <id column="id" property="id"/>
        <result property="username" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
        <!--
            property : 实体类中属性的名称
            ofType : 集合中的类型
            javaType: 返回值封装为什么类型
            column : user 表需要根据哪个字段去查询 account表
        -->
        <collection property="accounts" ofType="account" select="com.lyp.dao.AccountDao.findAccountByUid" column="id">
        </collection>
    </resultMap>
需要注意这里的column属性
  1. 使用延迟加载前后的区别:
使用延迟加载前
使用延迟加载之后

3.1 Demo地址

  1. Demo地址 : 一对一 一对多 实现懒加载

4. Mybatis 缓存

4.1 什么是缓存?

  1. 缓存是存在内存中的临时数据。

4.2 为什么使用缓存?

  1. 减少和数据库交互次数,提高执行效率。

4.3 什么样的数据适用于缓存?

  1. 经常查询并且不经常改变的。

  2. 数据的正确与否对最终结果影响不大的。

4.4 不适用于使用缓存的?

  1. 经常改变的数据;
  2. 数据的正确性对最终结果影响很大的;

4.5 Mybatis的一级缓存

4.5.1 Mybatis的一级缓存简介

  1. Mybatis的一级缓存指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,查询结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,Mbatis会先去SqlSession中查询是否有?有的话直接拿出来。

4.5.2 Mybatis中一级缓存Demo

  1. 创建一个普通的Maven工程,实现简单的查询所有User。

  2. 在findById方法中测试 :

  • 未关闭SqlSession
 /**
     * 根据 id 查询用户信息
     */
    @Test
    public void findById() {

        /*使用Mybatis SqlSession中的一级缓存进行测试*/
        User user1 = userDao.findById(50);
        System.out.println(user1);

        User user2 = userDao.findById(50);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }
未关闭SqlSession的情况
  • 关闭SqlSession之后
 /**
     * 根据 id 查询用户信息
     */
    @Test
    public void findById() {

        /*使用Mybatis SqlSession中的一级缓存进行测试*/
        User user1 = userDao.findById(50);
        System.out.println(user1);

        // 在此处关闭SqlSession
        session.close();
        // 重新获取一个SqlSession
        session = factory.openSession();

        userDao = session.getMapper(UserDao.class);

        User user2 = userDao.findById(50);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }
关闭SqlSession之后释放缓存
  • 除了使用关闭SqlSession释放缓存的方式之外,还可以使用SqlSession的clearCache()方法释放缓存
/**
     * 根据 id 查询用户信息
     */
    @Test
    public void findById() {

        /*使用Mybatis SqlSession中的一级缓存进行测试*/
        User user1 = userDao.findById(50);
        System.out.println(user1);

       /* // 在此处关闭SqlSession
        session.close();
        // 重新获取一个SqlSession
        session = factory.openSession();*/

       session.clearCache();

        userDao = session.getMapper(UserDao.class);

        User user2 = userDao.findById(50);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }

4.5.3 Mybatis中一级缓存如何做到同步

  1. Mybatis的一级缓存,当调用SqlSession的修改、添加、删除、commit()、close()等方法就会清空一级缓存。

  2. 在UserDao持久层接口中添加一个更新用户信息的方法。进行测试。

 /**
     * 更新用户信息
     * @param user
     */
    void updateUser(User user);
    <update id="updateUser" parameterType="user">
        update user set username = #{username} , address = #{address}
        where id = #{id}
    </update>
  1. 编写测试类进行测试:
    @Test
    public void testUpdateToCache() {
        User user1 = userDao.findById(41);
        user1.setUsername("update to first level cache");
        user1.setAddress("重庆市渝北区");
        userDao.updateUser(user1);
        System.out.println(user1);

        // 再次查询
        User user2 = userDao.findById(41);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }

4.6 Mybatis中的二级缓存

  1. 二级缓存概念:指的是Mybatis中SqlSessionFactory对象的缓存由同一个SqlSessiondFactory对象创建SqlSession共享其缓存。


    同一个SqlSessionFactory创建的SqlSession对象共享缓存

4.6.1 二级缓存的使用步骤

  1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)。可以不用设置因为默认值就是true。
在全局配置文件中开启对缓存的支持
  1. 在让当前的映射配置文件支持缓存(在UserDao.xml中配置)。


    在映射配置文件中开启对缓存的支持
  2. 让当前的操作支持二级缓存(在Select标签中配置)。

在Select标签中开启对缓存的支持

4.6.2 在测试类中编写测试类进行测试

/**
     * 测试Mybatis的二级缓存  同一个factory创建的SqlSession对象共享缓存 但是前提是需要让Mybatis支持二级缓存
     */
    @Test
    public void testMyabtisSecondLevelCache() {
        // 同一个factory创建的SqlSession对象共享缓存
        SqlSession session1 = factory.openSession();
        UserDao userDao1 = session1.getMapper(UserDao.class);
        User user1 = userDao1.findById(41);
        System.out.println(user1);
        session1.close();

        SqlSession session2 = factory.openSession();
        UserDao userDao2 = session2.getMapper(UserDao.class);
        User user2 = userDao2.findById(41);
        System.out.println(user2);
        session2.close();

        System.out.println(user1 == user2);
    }
未开启Mybatis对缓存的支持
报错:因为实体类未实现Serializable接口实现之后恢复正常
开启对缓存的支持之后

4.6.2 Demo地址

  1. Demo地址 : Mybatis实现一级缓存和二级缓存
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335