8. 缓存

8.1 一级缓存

在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。

MyBatis会在一次会话的表示一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。

一级缓存是Mybatis自带的缓存。

如下面的测试代码:

@Testpublic void testFirstCache() {//连续查了两次id=21的数据//dept1从数据库中查询,控制台会打印sql语句Dept dept1 = session.selectOne("DEPT.getDeptById", 21);//dept2从缓存中查询,控制台上没有sql输出Dept dept2 = session.selectOne("DEPT.getDeptById", 21);System.out.println(dept1.getName());System.out.println(dept2.getName());}

这段代码执行一次查询。

同一个SqlSession中,执行了任何一个update()、insert()、delete()或commit()后都会清空一级缓存。下面的测试代码会查询两次:

@Testpublic void testFirstCache() {//连续查了两次id=22的数据//dept1从数据库中查询,控制台会打印sql语句,放入缓存中Dept dept1 = session.selectOne("DEPT.getDeptById", 22);//使用进行增删改任何操作,或comimit()后都会清空缓存session.delete("DEPT.deleteDept", 27);session.commit();//因为前面进行了删除,所以缓存清空了,这里又会重新查询数据库Dept dept2 = session.selectOne("DEPT.getDeptById", 22);System.out.println(dept1.getName());System.out.println(dept2.getName());}

8.2 二级缓存

二级缓存需要用户去设置。二级缓存比一级缓存范围更大,一级缓存是一个SqlSession范围内的,不同的SqlSession之间不共享。而二级缓存可以实现多个SqlSession之间共享对同一个Mapper的缓存。

二级缓存需要在mybatis-config.xml中设置开启:

<settings><!--开启二级缓存--><setting name="cacheEnabled" value="true"/>
</settings>

注意<settings>节点要写在typeAliases之前,否则会报错。

在需要开始二级缓存的Mapper中加入<cache>节点开启缓存。如在DeptMapper.xml中开启缓存:

<mapper namespace="DEPT"><!--开启本Mapper的二级缓存--><cache></cache>

二级缓存要求放入缓存的pojo对象都必须实现java.io.Serializable接口:

public class Dept implements Serializable{

测试代码:

@Testpublic void testSecondCache() {//使用session1查询dept1从数据库中查询,控制台会打印sql语句SqlSession session1=sessionFactory.openSession();Dept dept1 = session1.selectOne("DEPT.getDeptById", 28);session1.close();//关闭session1,此时将dept1写入二级缓存//开启一个新的sessionSqlSession session2=sessionFactory.openSession();//因为session1已经将id=28的对象放到二级缓存中了,所以这里从缓存中取Dept dept2 = session2.selectOne("DEPT.getDeptById", 28);System.out.println(dept1.getName());System.out.println(dept2.getName());session2.close();}

增删改查的statement标签都有一个flushCache属性,默认是true****,即执行后刷新缓存。一般不去改它。避免数据出现脏读。

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

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

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

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

\1. LRU – 最近最少使用的:移除最长时间不被使用的对象。

\2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

\3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

\4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对

8.3 整合第三方缓存ehcache

ehcache缓存数据可以在内存和磁盘上缓存数据,无需担心容量问题。

Mybatis与ehcache结合使用,可以实现多个SqlSession对同一个Mapper的缓存共享。

8.3.1 导入jar包

使用ehcache需要导入jar包,在pom.xml中加入如下配置:

<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache-core</artifactId><version>2.4.4</version>
</dependency><dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.1.0</version>
</dependency>

8.3.2 创建ehcache配置文件

在resources目录下创建ehcache.xml文件:

<?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd"><defaultCache overflowToDisk="true" eternal="false"/><!--硬盘上存放数据的位置--><diskStore path="E:/tmp"/><!--缓存的配置,与Mybatis整合时,name等于Mapper的namespace--><cache name="DEPT" overflowToDisk="true" eternal="false"timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="2"maxElementsOnDisk="10" diskPersistent="true" diskExpiryThreadIntervalSeconds="300" diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU"/></ehcache>

参数说明:

name:Cache的唯一标识,与Mybatis结合使用时,name是Mapper的namespace

​ maxElementsInMemory:内存中最大缓存对象数

​ maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大

​ eternal:Element是否永久有效,一但设置了,timeout将不起作用

​ overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中

​ timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大

​ timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大

​ diskPersistent:是否缓存虚拟机重启期数据

​ diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒

​ diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区

​ memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。

8.3.3 开启Mybatis二级缓存

在mybatis-config.xml中开启二级缓存:

<settings><!--开启二级缓存--><setting name="cacheEnabled" value="true"/>
</settings>

8.3.4 在Mapper中设置缓存

在DeptMapper.xml中开启缓存:

<mapper namespace="DEPT"><!--开启本Mapper的二级缓存--><!--<cache ></cache>--><cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

测试代码:

@Testpublic void testEhCache() throws InterruptedException {//使用session1查询dept1从数据库中查询,控制台会打印sql语句SqlSession session1 = sessionFactory.openSession();Dept dept1 = session1.selectOne("DEPT.getDeptById", 28);List<Dept> list1 = session1.selectList("DEPT.getAllDept");session1.close();//关闭session1,此时将dept1写入缓存//查看缓存是否生效CacheManager cacheManager = CacheManager.getInstance();if (cacheManager.cacheExists("DEPT")) {Cache cache = cacheManager.getCache("DEPT");//可以看到缓存中写入了数据System.out.println(cache.getKeys());}//开启一个新的sessionSqlSession session2 = sessionFactory.openSession();//因为session1已经将id=28的对象放到二级缓存中了,所以这里从缓存中取//使用session2执行和session1一样的语句时,不会打印sqlDept dept2 = session2.selectOne("DEPT.getDeptById", 28);List<Dept> list2 = session2.selectList("DEPT.getAllDept");session2.close();
}

运行结果:

去磁盘上查看,可以看到缓存文件:

Mybatis一级缓存、整合第三方缓存ehcache、Mybatis二级缓存相关推荐

  1. Mybatis的一、二级缓存的原理与使用、禁止指定方法的二级缓存与刷新缓存、Mybatis整合Ehcache、二级缓存的使用场景与局限性-day03

    目录 第一节 Mybatis的缓存 1.1 Mybatis的缓存理解 1.2 一级缓存 原理 使用与测试 1.3 二级缓存 原理 使用与测试 禁用指定方法的二级缓存 刷新缓存 总结 1.4 整合ehc ...

  2. MyBatis 缓存详解-什么时候开启二级缓存?

    一级缓存默认是打开的,二级缓存需要配置才可以开启.那么我们必须思考一个问题,在什么情况下才有必要去开启二级缓存? 1.因为所有的增删改都会刷新二级缓存,导致二级缓存失效,所以适合在查询为主的应用中使用 ...

  3. ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存

    ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存 hibernate  : Hibernate是一个持久层框架,经常访问物理数据库 ...

  4. (12) Hibernate+EhCache配置二级缓存

    转载地址 http://jyao.iteye.com/blog/1315726 (有关EhCache的基础介绍可参见:http://sjsky.iteye.com/blog/1288257 ) 本文主 ...

  5. Hibernate EHCache - Hibernate二级缓存

    Hibernate EHCache - Hibernate二级缓存 欢迎使用Hibernate二级缓存示例教程.今天我们将研究Hibernate EHCache,它是最受欢迎的Hibernate二级缓 ...

  6. CPU一级缓存L1 D-cache\L1 I-cache与二级缓存L2 cache深度分析

    CPU缓存:通过优化的的读取机制,可以使CPU读取缓存的命中率非常高(大多数CPU可达90%左右), 也就是说CPU下一次要读取的数据90%都在缓存(SRAM)中: 只有大约10%需要从内存(DRAM ...

  7. MyBatis 延迟加载,一级缓存(sqlsession级别)、二级缓存(mapper级别)设置

    什么是延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再去加载关联信息 ...

  8. 开启mybatis日志_Mybatis源码分析之Cache二级缓存原理 (五)

    一:Cache类的介绍 讲解缓存之前我们需要先了解一下Cache接口以及实现MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(Ser ...

  9. mybatis事物如何避免脏读_MyBatis为了解决二级缓存脏读问题,究竟做了那些骚操作!...

    转自微信公众号[JAVA程序狗] 一.存在即合理 MyBatis为了提高我们的查询性能,专门设计了一级缓存和二级缓存,众所周知,我们在开发环境中,使用的缓存的时候,也会遇到各种各样的挑战,比如缓存穿透 ...

  10. mysql ehcache_MyBatis使用Ehcache作为二级缓存

    特别说明:由于二级缓存是基于Mapper的,当你在不同的mapper中查询了相同的数据,例如不同的Mapper中有多表查询时结果中有相同的数据,当其中一个Mapper进行插入更新缓存时,另一个并没有插 ...

最新文章

  1. SafeSEH原理与对抗
  2. haslayout详解
  3. Spring Boot 系列(五)web开发-Thymeleaf、FreeMarker模板引擎
  4. 在 Lotus Notes 中设置邮件定时发送的方法及代理功能介绍
  5. python怎么和sql一起用_自己写的Python数据库连接类和sql语句拼接方法
  6. 【Envi风暴】Envi 5.4遥感影像镶嵌原来如此简单!
  7. 【高等数学】一元函数积分表
  8. C#LeetCode刷题之#704-二分查找(Binary Search)
  9. 不实用额外变量 交换_变量交换:巧用异或运算
  10. 1)关于配置centos的网络问题
  11. 这款游戏玩法是Low了点,但赚的却是实打实的EOS。
  12. shell脚本 空格
  13. 05.日志框架与Spring Boot日志全篇
  14. 私塾在线 Java架构师在线课程(148讲教程)
  15. 惯导系统测试方法及测试系统
  16. IDEA+EmmyLua Lua开发环境搭建
  17. python统计分析-卡方分析和方差分析
  18. esp8266连接阿里云 (课程设计 附源码)
  19. 第56章 SQL UCASE() 函数教程
  20. 苹果怎么安装未签名的app_稳定不掉第三方app签名怎么弄

热门文章

  1. python网络编程学习笔记(二)
  2. 浅析概率中的频率学派观点和贝叶斯学派观点
  3. Integer类的装箱和拆箱到底是怎样实现的?
  4. POJ-1861-Network 解题报告
  5. WIndows thinpc 精简版的WIN7
  6. jquery查找元素方法示例
  7. 三种方法实现弹出框边框半透明和圆角的效果
  8. node-包管理工具 npm
  9. 7-42 关于堆的判断 (25 分)
  10. 图像处理-图像增强(三)