一,Mybatis中为什么要有缓存

  缓存的意义是将用户经常查询的数据放入缓存(内存)中去,用户去查询数据的时候就不需要从磁盘(关系型数据库)中查询,直接从缓存中查询,从而提高了查询效率,解决了高并发中系统的性能问题。Mybatis中提供一级缓存与二级缓存。

  Mybatis的一级缓存是一个SqlSession级别的缓存,只能访问自己的一级缓存数据,而二级缓存是Mapper级别的缓存,是跨SqlSession的,不同的SqlSession是可以共享缓存数据的。

二,一级缓存

  Mybatis 一级缓存原理:

  第一次发出查询请求,sql 查询的结果写入SqlSession的一级缓存当中,缓存使用的数据结构是一个map<key, value>

  1. key : hashcode + sql + sql输入参数 + 输出参数 (sql的唯一标识)
  2. value : 用户信息

  同一个SqlSession再次发出相同的sql,就会从缓存中读取而不走数据库,如果两次操作之间出现commit(修改、输出、添加)操作,那么本SqlSession中一级缓存区域全部清空,下次再去缓存中查不到所以要从数据库中查询,从数据库再写入一级缓存。

@Test
public void createTable(){SqlSession sqlSession = DBUtil.getSqlSession();List<Map<String, Object>> list1 = sqlSession.selectList("com.snow.xml.SnowOracle.getEmployeeByName", "周康");System.out.println(list);List<Map<String, Object>> list2 = sqlSession.selectList("com.snow.xml.SnowOracle.getEmployeeByName", "周康");System.out.println(list2);
}

  在数据库中有一张Employee表,里面有一条数据,通过selectList的方法查询,结果如下[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=36, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]

  此时,手动修改数据库该人的年龄,手动修改为35,然后保存

  此时,在运行代码,查看list2的值,两次结果一致,都是36 并非 35,说明第二次相同的查询走的是SqlSession中的一级缓存。

  Mybatis 中一级缓存需要注意的点 :

  1. Mybatis 中一级缓存是默认开启的,不需要手动配置。
  2. MybatisSpring 整合后进行 mapper 代理开发后,不支持一级缓存。MybatisSpring 整合,Spring 按照 mapper 的模板去生成 mapper 代理对象,模板中在最后会统一关闭 SqlSession

三、二级缓存

  Mybatis二级缓存原理:

  二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,结构是map<key, value>。每次查询前看是否开启了二级缓存,如果开启则从二级缓存的数据结构中取缓存数据,如果二级缓存中没有取到,再从一级缓存中取,如果一级缓存也没有,那就从数据库中查询。

  1. 二级缓存配置

  需要在Mybatis的配置文件中<settings>标签中配置二级缓存:

<settings><setting name="cacheEnabled" value="true"/> <!--Mybatis的二级缓存配置-->
</settings>

  Mybatis的二级缓存的范围是mapper级别的,因此我们mapper如果想要使用二级缓存,还需要在对应的映射文件中配置<cache>标签

<mapper namespace="com.snow.xml.SnowOracle"><cache></cache> <!--Mybatis的二级缓存配置-->
</mapper>

测试:

@Test
public void test(){SqlSession sqlSession1 = DBUtil.getSqlSession();List<Map<String, Object>> list1 = sqlSession1.selectList("getEmployeeByName", "周康");System.out.println("list1=" + list1);sqlSession1.commit();sqlSession1.close();DBUtil.closeSqlsession();SqlSession sqlSession2 = DBUtil.getSqlSession();List<Map<String, Object>> list2 = sqlSession2.selectList("getEmployeeByName", "周康");System.out.println("list2=" + list2);sqlSession2.commit();sqlSession2.close();
}

在SqlSession2 创建处打断点,观看此时输出:list1=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]

此时去修改数据库中周康此人的年龄,改为37提交,代码继续往下执行,会看到SqlSession2 与SqlSession1 是两个不同的SqlSession,观看此时输出:list2=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]


两次结果一致,均为35岁,说明SqlSession2 的查询没有走数据库,而是用了Mybatis的二级缓存,从里面拿到的数据,虽然是两个不同的SqlSession,但是二级缓存是mapper级别的,SqlSession1 只执行了查询操作没有增改删,所以不会清空二级缓存中的数据。

此处如果关闭了二级缓存的配置,查询出来的结果会是实时的,因为一级缓存默认开启,一级缓存的作用是SqlSession级别的,不同的SqlSession缓存数据不共享。这里就不演示一级缓存效果了。

  1. 禁用二级缓存

  有些情况下,我们需要打开二级缓存的配置,但是某个sql语句的查询变化频率较高,则需要针对该sql禁用二级缓存。在xml中statement中设置useCache=false 则可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认是true(使用二级缓存)

<select id="getEmployeeByName" parameterType="string" resultType="java.util.LinkedHashMap" useCache="false">SELECT E.ID, E.EMPNAME, E.AGE, GB01.DMGRP, E.BIRTHDATE, E.SALARY, E.ADDRESS, GB02.DMGRP AS GRADEFROM EMPLOYEE E LEFT JOIN GB01 ON E.SEX = GB01.ID LEFT JOIN GB02 ON E.GRADE = GB02.IDWHERE E.EMPNAME = #{name}
</select>

测试:
操作与上面一样,SqlSession2处打断点,更改数据库中该人的年龄,查看两次输出结果。


list1=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=37, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
list2=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]

可以看到操作虽然与第一次一样,可结果却变了,虽然二级缓存中有周康该人的信息,但是SqlSession2 还是从数据库中查询到了此人最新的数据,因为我们禁用了二级缓存。useCache=false

  1. 增删改的二级缓存

  二级缓存其实大部分都是为查询服务的,对于它们而言,如果我们缓存的数据不是最新的那么就会读到脏数据了。增删改之后之所以二级缓存会被清空是因为它们有一个默认的flushCache=true,默认在sql结束后刷新二级缓存,可以通过修改配置值达到不刷新缓存的目的(不建议使用)。

<update id="updateAgeByName" parameterType="string" flushCache="false">UPDATE EMPLOYEE SET AGE = '40' WHERE EMPNAME = #{EMPNAME}
</update>

四、了解Mybatis缓存的一些参数

  mybatis 的cache 参数只适用于mybatis 维护缓存。

flushInterval : 刷新间隔,可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式时间段,默认情况是不设置,也就是没有刷新间隔,缓存仅仅在调用语句时刷新。

size : 引用数目,可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目默认值为1024。

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

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

  这样的二级缓存配置,创建了一个FIFO的缓存,并且每隔60秒刷新,存数结果对象或列表的512个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。

默认的回收策略有(默认为LRU):

  1. LRU:最近最少使用的,移除最长时间不被使用的对象。
  2. FIFO:先进先出,俺对象进入缓存的顺序来移除它们。
  3. SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。
  4. WEAK:弱引用,更积极地移除给予垃圾回收器状态和弱引用规则的对象。

Mybatis 中的一级缓存与二级缓存相关推荐

  1. MyBatis中的一级缓存和二级缓存介绍

    先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,减轻数据库的压力,同时提高系统性能. 一级缓存 一级 ...

  2. java mysql 二级缓存_深入理解MyBatis中的一级缓存与二级缓存

    http://blog.csdn.net/weixin_36380516/article/details/73194758 先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中 ...

  3. 【mybatis】Mybatis中的一级、二级缓存

    [mybatis]简介 [mybatis]mybatis & mybatis-plus & hibernate的区别 [mybatis]核心成员分析 [mybatis]Mybatis的 ...

  4. mybatis中一级缓存和二级缓存

    1.一级缓存 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据.不同的sqlSessio ...

  5. MyBatis中一级缓存和二级缓存详解

    缓存的作用 首先缓存的合理使用是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,减轻数据的压力,同时提高系统性能. 为什么需 ...

  6. Mybatis一级缓存,二级缓存的实现就是这么简单

    介绍 又到了一年面试季,所以打算写一点面试常问的东西,争取说的通俗易懂.面试高级岗,如果你说熟悉Mybatis,下面这些问题基本上都会问 Mybatis插件的实现原理? 如何写一个分页插件? Myba ...

  7. mybatis高级(3)_延迟加载_深度延迟_一级缓存_二级缓存

    设置延迟加载需要在mybatis.xml中设置 注: 侵入式延迟加载为真时是延迟加载 侵入式延迟加载为假时是深度延迟加载 <!-- 延迟加载和深度延迟加载 --><settings& ...

  8. MyBatis框架:延迟加载策策略、一级缓存、二级缓存

    MyBatis框架:延迟加载策略和缓存 Mybatis 延迟加载策略 1.1 何为延迟加载? 1.2 实现需求 1.3 使用association实现延迟加载 1.3.1 账户的持久层DAO接口 1. ...

  9. 浅谈Mybatis的一级缓存和二级缓存

    MyBatis的缓存机制 缓存的引入 当我们大量执行重复的查询SQL语句的时候,会频繁的和数据库进行通信,会增加查询时间等影响用户体验的问题,可以通过缓存,以降低网络流量,使网站加载速度更快. MyB ...

最新文章

  1. 调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配
  2. linux中ps命令
  3. fsLayui缓存使用
  4. android146 360 病毒查杀
  5. php 动态加载JavaScript文件或者css文件
  6. linux下PS1命令提示符设置
  7. java的VIRT高的问题理解
  8. 监控 MySQL的多种方法
  9. [转载] OpenCV-Python图像位与运算bitwise_and函数详解
  10. [UWP]了解模板化控件(8):ItemsControl
  11. 数据可视化分析工具评测: DataEase (开源新贵)VS.帆软 FineBI(老牌产品)
  12. Schema hasn‘t been registered for model 解决方案
  13. java实现T检验(Ttest)
  14. 晶体晶振小结(XTAL与TCXO/VCXO/VC-OCXO等)-持续更新
  15. 第三代大数据处理方案Flink
  16. 树莓派3B+ 引脚图说明
  17. python django实验室药物管理预警系统
  18. 2.4G与5GWiFi频段的区别
  19. 小冰创作诗歌机制详解
  20. “悟空”来也!未上市就签几亿订单,看优必选机器人梦想的超级路径

热门文章

  1. Servlet MVC——CRUD
  2. 数据缺失处理——数据分析
  3. 机房维护 网拷_网络运行维护及机房应急方案计划
  4. 世界最小投影仪诞生!纽扣一样大小
  5. C++——转换字母的大小写
  6. 《上古天真论》第九讲文字版
  7. 集中注意力的方法(转)
  8. java借助modbus协议实现与设备的通讯,收发信息,实现对设备信息的采集
  9. Android数据库ObjectBox使用笔记[二]:查询操作
  10. 常用的几个富文本编辑器软件