理解mybatis中缓存
一级缓存(本地缓存):sqlSession级别的缓存,一级缓存一直都是开启的,sqlSession级别的Map,与数据库同一次回话期间查询到的数据都会放在本地缓存当中,以后如果要查询相同的数据,直接从缓存当中获取,而不要向数据库发送请求获得数据了。
//一级缓存的体验
@Test
public void test05() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
try {
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//根据id查询数据
Employee employee = employeeMapper.getEmployeeById(1);
System.out.println(employee);
//再次查询
Employee employee2 = employeeMapper.getEmployeeById(1);
System.out.println(employee2);
} finally {
sqlSession.close();
}
}
查询的结果:只会向数据库发送一次请求。
DEBUG 04-15 22:17:55,203 ==> Preparing: SELECT `id`, `lastname`, `email`, `birth`, `createtime`, `emp_image`, `department_id` FROM `employee` WHERE id=? (BaseJdbcLogger.java:145)
DEBUG 04-15 22:17:55,292 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-15 22:17:55,328 <== Total: 1 (BaseJdbcLogger.java:145)
Employee [id=1, lastname=刘东平, email=1846882398@qq.com, birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
Employee [id=1, lastname=刘东平, email=1846882398@qq.com, birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
思考:那些情况,一级缓存会失效?
1.sqlSession对象不是同一个对象了,就是说出现了两次会话了。
2.如果sqlSession相同,但是查询的条件不同,很显然还是会发送请求,因为你的缓存中没有数据,所以查询条件不同,还会进行。
3.如果sqlSession相同,但是在期间进行了增删改,那么也会发送sql语句,因为进行数据库操作必然会发送变化。
4.如果sqlSession相同,但是我们手动清除了缓存(sqlSession.clearCache()。
*二级缓存(全局缓存):*二级缓存是基于namespace级别的缓存机制,也就是说一个namespace就对应着一个的二级缓存。
二级缓存的工作机制:
1.一个会话,查询一条数据。这个数据就会放在当前会话的一级缓存当中,
2.如果该会话关闭了,一级缓存中保存的数据会保存到二级缓存中,新的回话查询信息,就可以参照二级缓存中的数据进行,选择性的知道自己是否该发送sql语句了
3.sqlSession===EmployeeMapper=>Employee
sqlSession=>DepartmentMapper=>department
不同的namespace查出的数据会保存在自己的缓存当中(Map)
二级缓存(second level cache),全局作用域缓存
• 二级缓存默认不开启,需要手动配置
• MyBatis提供二级缓存的接口以及实现,缓存实现要求
POJO实现Serializable接口
• 二级缓存在 SqlSession 关闭或提交 之后才会 生效
怎么使用二级缓存:
1.需要在mybatis-config.xml配置文件中配置:
<settings>.
<setting name="cacheEnabled" value="true"/>
</setteings>
2.需要在xxxxMapper.xml文件内配置
<cache></cache>
3.每个pojo都必须实现序列化接口
• 使用步骤
– 1、全局配置文件中开启二级缓存
• <setting name= "cacheEnabled" value="true"/>
– 2、需要使用二级缓存的映射文件处使用cache配置缓存
• <cache />
– 3、注意:POJO需要实现Serializable接
缓存相关属性
• eviction=“ FIFO” :缓存回收策略:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU
。*
• flushInterval :刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
• size :引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
• readOnly :只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象
不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,
但是安全,因此默认是 false。
1、全局setting的cacheEnable:
– 配置二级缓存的开关。一级缓存一直是打开的。
• 2、select标签的useCache属性:
– 配置这个select是否使用二级缓存。一级缓存一直是使用的
• 3、sql标签的flushCache属性:
– 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。
查询默认flushCache=false。
• 4、sqlSession.clearCache():
– 只是用来清除一级缓存。
• 5、当在某一个作用域
(一级缓存Session/二级缓存 Namespaces) 进行了
C/U/D 操作后,默认该作用域下 所有 select 中的缓存将被 clear
配置之后体验二级缓存
//二级缓存的体验
@Test
public void test06() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
try {
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
EmployeeMapper employeeMapper2 = sqlSession2.getMapper(EmployeeMapper.class);
//根据id查询数据
Employee employee = employeeMapper.getEmployeeById(1);
System.out.println(employee);
sqlSession.close();
//再次查询
Employee employee2 = employeeMapper2.getEmployeeById(1);
System.out.println(employee2);
} finally {
sqlSession2.close();
}
}
查询的打印结果:只会打印一条SQL语句
DEBUG 04-15 23:09:50,016 Cache Hit Ratio [com.ldp.mybatis.dao.EmployeeMapper]: 0.0 (LoggingCache.java:62)
DEBUG 04-15 23:09:50,026 ==> Preparing: SELECT `id`, `lastname`, `email`, `birth`, `createtime`, `emp_image`, `department_id` FROM `employee` WHERE id=? (BaseJdbcLogger.java:145)
DEBUG 04-15 23:09:50,092 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-15 23:09:50,127 <== Total: 1 (BaseJdbcLogger.java:145)
Employee [id=1, lastname=刘东平, email=1846882398@qq.com, birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
DEBUG 04-15 23:09:50,257 Cache Hit Ratio [com.ldp.mybatis.dao.EmployeeMapper]: 0.5 (LoggingCache.java:62)
Employee [id=1, lastname=刘东平, email=1846882398@qq.com, birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
细节:第一次查询的会话完毕或者关闭后,一级缓存中的数据才会转移到二级缓存当中。
缓存相关的设置:
1.cacheEnabled=true|false 关闭的是二级缓存,一级缓存一直都会存在。
2.每个select标签都会有useCache=true|false:不使用二级缓存。不影响一级缓存
3.每个增删改上面也会有flushCache=true||false
增删改执行完之后,清除缓存
测试:为true 一级缓存会被清除,二级必然也会清除。
查询标签也会有相应的情况出现:
4.sqlSession.clearCache:只是清除当前sqlSession的一级缓存
5.localCacheScope(本地缓存):(一级缓存session)存放数据
**
一级缓存和二级缓存的总结:
**
第三方(ehcache)的二级缓存实现:
1.导入第三方的缓存包ehcache-core-2.6.8.jar
2.导入整合包mybatis-ehcache-1.0.3.jar 两个日志包slf4j-api-1.6.1.jar… slf4j-log4j12-1.6.2.jar
3.加入ehcache.xml文件
4.在需要添加二级缓存的配置文件添加
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache> |
---|
其中ehcache.xml文件内容
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\44\ehcache" />
<defaultCache
maxElementsInMemory="10000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
<!--
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->