zoukankan      html  css  js  c++  java
  • Mybatis(四) Mybatis缓存

    4.1 Mybatis缓存概念

      缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存,我们可以避免频繁的与数据进行交互,进而提高响应速度。
    Mybatis 也提供了对缓存的支持,分为一级缓存和二级缓存,通过下图来理解:
    image.png

    1. 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession2直接的缓存区域(HashMap)是互相不影响。
    2. 二级缓存是Mapper级别的缓存,多个SqlSession去操作同一个Mapper查询的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

    4.2 一级缓存

    4.2.1 一级缓存案例

      mybatis一级缓存是默认开启的

     @Test
     public void firstLevelCache() throws IOException {
         InputStream resourceAsSteam = Resources.getResourceAsStream("sqlMapperConfig.xml");
         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsSteam);
         SqlSession sqlSession = sqlSessionFactory.openSession();
         UserDao userDao = sqlSession.getMapper(UserDao.class);
        User byUserId = userDao.findByUserId(1);
        User user = userDao.findByUserId(1);
        System.out.println(byUserId == user);
    }
    #输出结果 true
    

      第一次查询是会打出查询日志,第二次不会,而且两次查出的user地址是同一个,证明了一级缓存开启了。

     @Test
        public void firstLevelCache() throws IOException {
            InputStream resourceAsSteam = Resources.getResourceAsStream("sqlMapperConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsSteam);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User byUserId = userDao.findByUserId(1);
    				//添加修改操作
            User upuser = new User();
            upuser.setUsername("helo");
            upuser.setId(1);
            userDao.updateUser(upuser);
            sqlSession.commit();
    
            User user = userDao.findByUserId(1);
            System.out.println(byUserId == user);
        }
     #输出结果  false
    

    4.2.2 总结

    1. 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中
    2. 如果中间SqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样做的目的是为了让缓存中存储的是最新的信息,避免脏读
    3. 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

    image.png

    4.2.3 一级缓存解析

      一级缓存到底是什么?一级缓存什么时候被创建的、一级缓存的工资流程是怎么样的?
    image.png

    4.3 二级缓存

      二级缓存的原理和一级缓存原理一样,第一次查询会将数据放入缓存中,然后第二次查询则会直接去缓存中取。但是一级缓存是基于SqlSession的,而二级缓存是基于mapper文件的namespace的,也就是说多个SqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper中执行SQL查询到的数据也将存在相同的二级缓存区域中。
    image.png

    4.3.1 开启二级缓存

    二级缓存需要手动开启,sqlMapperConfig.xml中配置如下:

    <settings>
    	<settting name=cacheEnabled" value="true" />
    <settings>
    

    在UserMapper.xml中添加

      //二级缓存默认实现的是 PerpetualCache 类

    @Test
    public` `void` `testTwoCache(){
     SqlSession sqlSession1 = sessionFactory.openSession();
     SqlSession sqlSession2 = sessionFactory.openSession();
     
     UserMapper userMapper1 = sqlSession1.getMapper(UserMapper. class );
     UserMapper userMapper2 = sqlSession2.getMapper(UserMapper. class );
     //第一次查询,打印了sql语句,并把查询结果放入到缓存中
     User u1 = userMapper1.selectUserByUserId(1);
     System.out.println(u1);
     sqlSession1.close(); //一次查询后关闭SqlSession
     
     //执行更新操作commit(),会更新二级缓存
     u1.setUsername( "aaa" );
     userMapper3.updateUserByUserId(u1);
     sqlSession3.commit()
     
     //第二次查询,即使sqlSession已经关闭了,这次查询依然不发出sql语句
     User u2 = userMapper2.selectUserByUserId(1);
     System.out.println(u2);
     sqlSession2.close();
     System.out.println(u1 == u2) //结果为false
     }
    

      注:二级缓存保存的是查询出来的数据,u2是底层重新生成的User;开启了二级缓存后,还需要将缓存的pojo实现Serializable接口,为了将缓存数据取出来执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如我们要再取出这个缓存的话,就要反序列化。

    4.3.2 useCache和flushCache

      useCache是用来设置二级缓存的,如果设置为false,则表示禁止二级缓存,每次执行这条语句的时候都是从数据库里面查询数据,默认是true
    在mapper中,执行了insert和update,delete等操作时需要刷新缓存,不然会出现脏读的情况,flushCache神色中为true时表示这个sql语句要刷新缓存,默认为true

    <select id="selectUserByUserId" useCache="false"
      resultType="com.lagou.pojo.User" parameterType="int">
       select * from user where id=#{id}
    </select>
    
  • 相关阅读:
    EasyUI-datagrid-自动合并单元格(转)
    js中格式化时间字符串
    ext 3.2 tree 在IE10中点击事件失效的bug
    C#中修改Dll文件 (反编译后重新编译)
    GridView内容<br />换行
    使用Aspose.Words把 word转成图片
    判断移动设备访问自动跳转到移动版页面
    jquery mobile界面数据刷新
    Ubuntu16.04下安装Visual Studio Code
    npm 安装vue 报错Failed at the chromedriver@2.46.0 install script 'node install.js'
  • 原文地址:https://www.cnblogs.com/benjaming0321/p/12546905.html
Copyright © 2011-2022 走看看