zoukankan      html  css  js  c++  java
  • Mybatis缓存理解

    缓存

    接触过hibernate的同学都知道hibernate中有个二级缓存,mybatis也存在二级缓存。mybatis中二级缓存有什么作用呢?mybatis提供查询缓存,可以提高查询效率,减轻数据库的压力。

    一级缓存

    一级缓存是session级别的缓存,基于PerpetualCache的HashMap本地存储,其存储作用域为Session,不能跨不同的session,当Session flush或close之后,该Session中的所有Cache就将清空。

    SqlSession session = sqlSessionFactory.openSession();
    FootballMatchMapper footballMatchMapper = session.getMapper(FootballMatchMapper.class);
    FootballMatch footballMatch = footballMatchMapper.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch.getHomeTeamName());
    
    //重复查询同一条记录时,一级缓存开始使用
    footballMatch = footballMatchMapper.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch.getHomeTeamName());
    
    //session关闭,session中的cache将被清除
    session.close();
    session = sqlSessionFactory.openSession();
    footballMatchMapper = session.getMapper(FootballMatchMapper.class);
    footballMatch = footballMatchMapper.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch.getHomeTeamName());
    
    footballMatch = footballMatchMapper.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch.getHomeTeamName());
    
    //sqlSession执行insert、update、delete等操作commit提交后会清空缓存区域
    footballMatch.setUpdateTime(new Date());
    footballMatchMapper.updateByPrimaryKeySelective(footballMatch);
    footballMatch = footballMatchMapper.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch.getHomeTeamName());

    通过日志分析一下: 
    同一个session作用域内,相同查询结果会从缓存中取,不会重复从数据库查询。当session关闭之后,该Session中的所有Cache就将清空,从而从数据库查询: 

    update操作之后会清空缓存区域,使缓存失效,从而执行数据库查询: 

    二级缓存

    二级缓存是mapper级别的缓存,它的实现机制跟一级缓存差不多,也是基于PerpetualCache的HashMap本地存储。作用域为mapper的namespace,可以自定义存储,比如Ehcache。Mybatis的二级缓存是跨Session的,每个Mapper享有同一个二级缓存域.

    Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的Java对象。

    SqlSession session1 = sqlSessionFactory.openSession();
    FootballMatchMapper footballMatchMapper1 = session1.getMapper(FootballMatchMapper.class);
    FootballMatch footballMatch = footballMatchMapper1.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch.getHomeTeamName());
    session1.close();
    
    SqlSession session2 = sqlSessionFactory.openSession();
    FootballMatchMapper footballMatchMapper2 = session2.getMapper(FootballMatchMapper.class);
    FootballMatch footballMatch2 = footballMatchMapper2.selectByPrimaryKey("20180115004");
    System.out.println(footballMatch2.getHomeTeamName());
    session2.close();

    如果两个mapper文件的命名空间一样,他们就可以共享一个mapper缓存。每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存。

    开启缓存

    二级缓存是需要配置来开启的:

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

    非常简单,在Mybatis的核心配置文件中加上上面这行代码,然后在Mapper映射文件中添加一行:

    <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

    表示开启二级缓存,flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。 size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。 readOnly(只读)属性可以被设置为true或false。

    只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

    如果已经开启二级缓存的mapper里面某个查询不需要缓存,可以使用useCache=”false”禁用二级缓存:

    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" useCache="false">

    刷新缓存

    在mapper的同一个namespace中,如果有其他insert、update、delete操作后都需要执行刷新缓存操作,来避免脏读。

    这时我们只需要设置statement配置中的flushCache=“true“属性,就会默认刷新缓存,相反如果是false就不会了。

    当然,不管开不开缓存刷新功能,你要是手动更改数据库表,那都肯定不能避免脏读的发生,那就属于手贱了。

    无论是一级缓存还是二级缓存,C/U/D增删改操作commit提交后会清空缓存区域,使缓存失效。合理利用二级缓存可以提高系统性能,减少数据库压力。但是,如果使用不当可那个会出现缓存一致性问题,对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度。

    本文转自:https://blog.csdn.net/chengbinbbs/article/details/79215783

  • 相关阅读:
    左边菜单导航
    css3实现轮播
    js-统计选项个数
    空间评论。回复。点赞功能
    简单的购物车功能
    字符串常用的几种方法
    React,js实现分页的案列
    python2的cgi程序
    开发环境和工具
    github入门
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/9412864.html
Copyright © 2011-2022 走看看