mybatis中的缓存

mybatis中的缓存

  1. 什么是缓存?

    缓存就是存在内存中的临时数据

  2. 为什么使用缓存?

    减少和数据库中的交互次数,提高执行效率

  3. 什么样的数据可以使用缓存,什么样的数据不能使用缓存?

    适用:

    ​ 经常查询并且不经常改变的数据

    ​ 数据的正确与否对最终结果影响不大的时候

    不适用:

    ​ 经常改变的数据

    ​ 数据的正确与否对最终结果影响很大的

    ​ 例如:商品的库存,银行的汇率

mybatis中的一级缓存与二级缓存

  • 一级缓存:

    指的是mybatis中SqlSession对象的缓存。

    当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有这个数据,有的话会直接拿出来用,而不再去数据库中查询。

    当SqlSession对象消失时,mybatis一级缓存也就消失了。

        @Test
        public void firstLevelCatch(){
            System.out.println("---------------------------------------------------------------------------");
            User user = userDao.selectOne(1);
            System.out.println(user);
            
            System.out.println("---------------------------------------------------------------------------");
            User user1 = userDao.selectOne(1);
            System.out.println(user1);
            System.out.println("---------------------------------------------------------------------------");
        }
    

    当执行单表的按ID查询方法时,执行两次该方法,看log4j的打印信息。在第一次的时候是从数据库里查找出来信息,第二次时就是从缓存中将上一次的消息再次拿出来

    DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
    Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    ---------------------------------------------------------------------------
    Opening JDBC Connection
    Created connection 1073533248.
    Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3ffcd140]
    ==>  Preparing: select * from user where id = ?;
    ==> Parameters: 1(Integer)
    <==    Columns: id, name, age, birthday
    <==        Row: 1, 1, 1, 2020-12-03 14:17:30.0
    <==      Total: 1
    User{id=1, name='1', age=1, birthday=Thu Dec 03 14:17:30 CST 2020}
    ---------------------------------------------------------------------------
    User{id=1, name='1', age=1, birthday=Thu Dec 03 14:17:30 CST 2020}
    ---------------------------------------------------------------------------
    
    Process finished with exit code 0
    

    这是控制台的打印信息,我在两次查询中间用了同样的短线进行划分,可以很明显的看出,第一次在数据库中进行了查找,第二次没有。

    那如何直接清理掉SqlSession中的缓存呢?有两种方式:

    1. 就是关闭SqlSession,然后再重新创建一个SqlSession,这样,以前的SqlSession就会消失,缓存自然也会消失
    2. 调用方法,调用SqlSession的clearCache()方法来清空缓存。

    第一种方法我们不多做赘述,来看下第二种方法的效果

        @Test
        public void firstLevelCatch(){
            System.out.println("---------------------------------------------------------------------------");
            User user = userDao.selectOne(1);
            System.out.println(user);
            session.clearCache();
            System.out.println("---------------------------------------------------------------------------");
            User user1 = userDao.selectOne(1);
            System.out.println(user1);
            System.out.println("---------------------------------------------------------------------------");
        }
    

    这是执行方法,可以看出两次查询中间添加了清理缓存的方法

    DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
    Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    ---------------------------------------------------------------------------
    Opening JDBC Connection
    Created connection 1073533248.
    Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3ffcd140]
    ==>  Preparing: select * from user where id = ?;
    ==> Parameters: 1(Integer)
    <==    Columns: id, name, age, birthday
    <==        Row: 1, 1, 1, 2020-12-03 14:17:30.0
    <==      Total: 1
    User{id=1, name='1', age=1, birthday=Thu Dec 03 14:17:30 CST 2020}
    ---------------------------------------------------------------------------
    ==>  Preparing: select * from user where id = ?;
    ==> Parameters: 1(Integer)
    <==    Columns: id, name, age, birthday
    <==        Row: 1, 1, 1, 2020-12-03 14:17:30.0
    <==      Total: 1
    User{id=1, name='1', age=1, birthday=Thu Dec 03 14:17:30 CST 2020}
    ---------------------------------------------------------------------------
    
    Process finished with exit code 0
    

    这是控制台的打印效果,可以看出,进行了两次数据库的查询操作。

    :一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。(请自行验证)

  • 二级缓存

    在这里插入图片描述

    指的是mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存

    二级缓存的使用步骤:

    1. 让mybatis框架支持二级缓存(在mybatis配置文件中配置)

      <setting name="cacheEnabled" value="true"/>
      

      也可以不配置,默认为true

    2. 让当前的映射文件支持二级缓存(到接口配置文件中配置)

      在接口配置文件的mapper标签下添加

      <cache></cache>
      
    3. 让当前的操作支持二级缓存(select标签中配置)

      然后在要实现二级缓存的语句标签上加入useCache=“true”

      <select id="selectOne" parameterType="com.lut.domain.User" useCache="true" resultType="com.lut.domain.User">
          select * from user where id = #{id};
      </select>
      

    当完成以上配置,在测试类中创建两个SqlSession,调用同一个查询方法,查询同一个值,第二次查询是从缓存中取,如果不实现二级缓存,是分别从数据库查询

        @Test
        public void firstLevelCatch(){
            System.out.println("---------------------------------------------------------------------------");
            SqlSession session = factory.openSession();
            IUserDao userDao = session.getMapper(IUserDao.class);
            User user = userDao.selectOne(1);
            System.out.println(user);
            session.close();
            System.out.println("---------------------------------------------------------------------------");
            SqlSession session1 = factory.openSession();
            IUserDao userDao = session1.getMapper(IUserDao.class);
            User user1 = userDao.selectOne(1);
            System.out.println(user1);
            session1.close();
            System.out.println("---------------------------------------------------------------------------");
        }
    

注:一级缓存存储的是对象,所以两次查询对象相等

​ 二级缓存存储的是数据,所以两次查询对象不相等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值