Mybatis——一级缓存与二级缓存

关于Mybatis的学习主要参考了狂神的视频

  1. 一级缓存

    (1).使用范围:从sqlSession会话开始到结束

    (2).使用:默认打开,无法关闭

    (3).测试使用(需要打开日志观察数据库的连接情况):

    public static void Maintest(){
        SqlSession sqlSession = Connection.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        HashMap map = new HashMap();
        map.put("UId","3180421016");
        List<UserBean> userBeans = userMapper.queryByIf(map);
        map.put("UName","关晨亮");
        //userMapper.updateById(map);
        System.out.println(userMapper.queryByIf(map).get(0).equals(userBeans.get(0)));
        sqlSession.close();
    }
    //result:true,将结果集打印,可以看出两次结果集打印之间是没有再做数据库连接的
    

    (4).缓存失效的4种情况:

    • sqlSession不同

      public static void Maintest(){
          SqlSession sqlSession1 = Connection.getSqlSession();
          SqlSession sqlSession2 = Connection.getSqlSession();
          UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
          UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
          HashMap map = new HashMap();
          map.put("UId","3180421016");
          List<UserBean> userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          sqlSession1.close();
          System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0)));
          sqlSession2.close();
      }
      
    • sqlSession相同,两次查询操作之间存在增删改操作

      public static void Maintest(){
          SqlSession sqlSession = Connection.getSqlSession();
          UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
          HashMap map = new HashMap();
          map.put("UId","3180421016");
          List<UserBean> userBeans = userMapper.queryByIf(map);
          map.put("UName","关晨亮");
          userMapper.updateById(map);
          System.out.println(userMapper.queryByIf(map).get(0).equals(userBeans.get(0)));
          sqlSession.close();
      }
      
      //result:false,将结果集打印,可以看出两次结果集打印之间是有再次做过数据库连接的
      
    • sqlSession相同,查询条件不同(此时缓存中没有相关数据)

      public static void Maintest(){
          SqlSession sqlSession1 = Connection.getSqlSession();
          UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
          HashMap map = new HashMap();
          map.put("UId","3180421016");
          List<UserBean> userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          map.put("UId","2");
          userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          sqlSession1.close();
      }
      //打开日志可以看到,发生了两次对于数据库的连接请求
      
    • 通过session.clearCache()主动刷新缓存

      public static void Maintest(){
          SqlSession sqlSession1 = Connection.getSqlSession();
          UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
          HashMap map = new HashMap();
          map.put("UId","3180421016");
          List<UserBean> userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          sqlSession1.clearCache();
          userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          sqlSession1.close();
      }
      
  2. 二级缓存

    (1).简介

    • 作用范围:整个namespace,也就是一个mapper
    • 实现:不同的mapper查出的数据会放在对应的缓存(map)中

    (2).使用:

    • 在主配置文件中显式地开启二级缓存
    <settings>
        <!--        <setting name="logImpl" value="LOG4J"/>-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
    • 在Mapper.xml中配置(为什么要开启readOnly会在后面解释)
    <cache readOnly="true"/>
    

    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    
    • 测试
    public static void Maintest(){
        SqlSession sqlSession1 = Connection.getSqlSession();
        SqlSession sqlSession2 = Connection.getSqlSession();
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
        HashMap map = new HashMap();
        map.put("UId","3180421016");
        List<UserBean> userBeans = userMapper1.queryByIf(map);
        sqlSession1.close();
        System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0)));
        sqlSession2.close();
    }
    /result:true
    

    (3).注意

    • 需要实体序列化

    客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要站用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。

    web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。

    将HttpSession对象保存到文件系统或数据库中,需要采用序列化的方式将HttpSession对象中的每个属性对象保存到文件系统或数据库中;将HttpSession对象从文件系统或数据库中装载如内存时,需要采用反序列化的方式,恢复HttpSession对象中的每个属性对象。所以存储在HttpSession对象中的每个属性对象必须实现Serializable接口

    public class UserBean implements Serializable {
        private String UId;
        private String UName;
        private int USet;
        private int UAuth;
        private String UPassword;
        private int UState;
    }
    
    • 必须打开只读,否则两次比较的结果不同

    只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。

    <cache readOnly="true"/>
    
    • 缓存优先放在以及会话中,当会话关闭后,缓存才会被转移到二级会话

      public static void Maintest(){
          SqlSession sqlSession1 = Connection.getSqlSession();
          SqlSession sqlSession2 = Connection.getSqlSession();
          UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
          UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
          HashMap map = new HashMap();
          map.put("UId","3180421016");
          List<UserBean> userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0)));
          sqlSession1.close();
          sqlSession2.close();
      }
      //false,因为还没有关闭就开始比较了
      
      public static void Maintest(){
          SqlSession sqlSession1 = Connection.getSqlSession();
          SqlSession sqlSession2 = Connection.getSqlSession();
          UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
          UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
          HashMap map = new HashMap();
          map.put("UId","3180421016");
          List<UserBean> userBeans = userMapper1.queryByIf(map);
          System.out.println(userBeans);
          sqlSession1.close();
          System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0)));
          sqlSession2.close();
      }
      //true,因为是会话关闭之后再比较的
      
    • 对于查询(select),我们可以使用useCache来选择是否取消缓存;对于增删改,可以使用flushCache来选择是否取消更新缓存

  3. 缓存原理,这边用狂神的图来加深理解

  4. 使用ehcache外部缓存

    (1).导包

    (2).写配置文件.xml

    (3).在主配置文件中使用:设定cache标签的type属性

    注:现在多用redis数据库

猜你喜欢

转载自www.cnblogs.com/Arno-vc/p/13375866.html