MyBatis框架:缓存机制,mybatis整合ehcache

mybatis缓存机制

简介

MyBatis 包含一个非常强大的查询缓存特性,
它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存。

一级例子

			EmpMapper mapper = openSession.getMapper(EmpMapper.class);
			Emp empById = mapper.getEmpById(3);
			System.out.println(empById);
			Emp empById2 = mapper.getEmpById(3);
			System.out.println(empById==empById2);
结果是:
只发了一条sql语句,两个emp的内存地址是一样的
DEBUG 05-19 11:55:59,176 ==>  Preparing: select eid id,ename name,email,gender from emp where eid= ?   (BaseJdbcLogger.java:145) 
DEBUG 05-19 11:55:59,199 ==> Parameters: 3(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 05-19 11:55:59,220 <==      Total: 1  (BaseJdbcLogger.java:145) 
Emp [eid=3, ename=, email=jane.com, gender=, dept=null]
true

一级,二级缓存机制

	/*
	 * mybatis的缓存机制
	 * 分为两级缓存:
	 * 	一级缓存:(本地缓存):sqlSession级别的缓存,sqlsession级别的一个Map
	 * 			一级缓存是一直开启的,我们关闭不了
	 * 			与数据库同一次会话期间查询到的数据会放在本地缓存中,
	 * 			以后如果需要获取相同的数据,直接从缓存中拿,
	 * 			没有必要再去查询数据库
	 * 		
	 * 		一级缓存失效的情况:
	 * 		就是没有使用到当前一级缓存的情况,效果就是查询相同的数据还需要向数据库发出sql语句
	 * 		1.sqlsession不同了
	 * 		2.sqlsession相同,查询条件不同了,因为当前一级缓存里面没有这个数据
	 * 		3.sqlsession相同,两次查询之间执行了增删改操作,因为这个增删改的操作可能对当前的数据有影响
	 * 		4.sqlsession相同,手动清除了一级缓存,调用了openSession.clearCache();
	 * 
	 * 	二级缓存:(全局缓存)
	 * 			这是基于namespace级别的缓存,一个namespace就对应一个二级缓存
	 * 		机制原理:
	 * 		1.一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中
	 * 		2.如果会话关闭,一级缓存中的数据就会被保存到二级缓存中
	 * 				新的会话查询数据,就可以参照二级缓存的内容
	 * 		3.sqlsession会话在EmpMapper中查询了Emp信息
	 * 						在DeptMapper中查询了Dept信息
	 * 						这两个不同的缓存信息是不能互相使用的
	 * 				不同的namespace查出的数据会放在自己对应的缓存中(就是map)
	 * 		效果:数据会从二级缓存中获取
	 * 		注意:查出的数据会默认先放在一级缓存中的,
	 * 			只有会话提交或者关闭后,一级缓存中的数据才会转移到二级缓存中
	 * 			所以测试的时候,两个不同的会话调用同一个数据想使用缓存
	 * 			必须在第二个会话调用前关闭第一个会话
	 * 		如何使用:
	 * 				1.开启全局二级缓存配置,其实默认是开启的,
	 * 					但是我们默认是将自己需要的设置都写上
	 * 					<setting name="cacheEnabled" value="true"/>
	 * 				2.哪一个映射文件需要使用二级缓存
	 * 					在映射文件加上<cache></cache>标签
	 *				3.因为缓存使用到序列化技术,每个POJO都要实现序列化接口
	 * 
	 * 	使用缓存的一些小设置:
	 * 		1.cacheEnabled=true
	 * 						false:关闭二级缓存,一级缓存是一直可以使用的
	 * 		2.每一个select标签都有useCache="true";的设置
	 * 										false:就是不使用二级缓存,一级缓存还是可以使用的
	 * 		3.每一个增删改标签都有默认的flushCache="true":(一级缓存,二级缓存都会被清除)
	 * 					这个属性让增删改执行完成后清除缓存
	 * 					flushCache="true":一级缓存,二级缓存都会被清除)
	 * 				而查询标签默认的flushCache="false",
	 * 				而查询标签将flushCache="true",那么每次查询后就会清空缓存,缓存时没有被使用的
	 * 		4.手动调用的sqlSession.clearCache(),只是清除当前的一级缓存,二级不会清除
	 * 		5.全局设置还有这样一个参数:localCacheScope:本地缓存的作用域
	 * 				有两个取值:
	 * 					SESSION:一级缓存,当前会话的所有数据保存在会话缓存中;
	 * 					STATEMENT:没有一级缓存了,相当于禁用了一级缓存
	 */
	
	@org.junit.Test
	public void test9() throws IOException
	{
		String resource = "mybatis.xml"; 
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		try
		{
			SqlSession openSession1 = sqlSessionFactory.openSession();
			SqlSession openSession2 = sqlSessionFactory.openSession();
			EmpMapper mapper1 = openSession1.getMapper(EmpMapper.class);
			EmpMapper mapper2 = openSession2.getMapper(EmpMapper.class);
			
			Emp empById = mapper1.getEmpById(7);
			System.out.println(empById);
			
			openSession1.close();
			Emp empById2 = mapper2.getEmpById(7);
			System.out.println(empById2);
			openSession2.close();
			
		}finally
		{
		}
	}

	<cache eviction="FIFO" flushInterval="10000" readOnly="false" size="1024" ></cache>
	<!-- 
		eviction:缓存回收策略:
				LRU – 最近最少使用的:移除最长时间不被使用的对象。 
				FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 
				SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。 
				WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 
				默认的是 LRU。 
		flushInterval:缓存刷新间隔
						缓存多长时间清空一次,默认不清空,设置一个毫秒值
		readOnly:是否只读,取值是布尔值
			true:只读:mybatis认为所有从缓存中获取数据的操作都是只读的,不会修改数据
					  mybatis为了加快获取速度,直接将数据在缓存中的引用交给用户
					  这样速度是快了,但是这样不安全
			false:非只读,mybatis觉得获取的数据可能被修改
						所以就先会利用序列化和反序列化的技术克隆一份新的数据给你
						这样安全,但是速度慢
		size:缓存存放多少个元素
		type:指定自定义的全类名,自定义的类需要实现Cache接口
	 -->

POJO

public class Emp implements Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Integer eid;
	private String ename;
	private String email;
	private String gender;
	private Dept dept;

结果:
可以发现,第二次拿到的结果不是发sql得到的,而是
DEBUG 05-20 12:51:52,960 Cache Hit Ratio [bean.EmpMapper]: 0.5  (LoggingCache.java:62) 
直接从二级缓存里面获取,获取了两次,第二次获取成功,所以后面的数字是1/2=0.5

DEBUG 05-20 12:51:52,791 Cache Hit Ratio [bean.EmpMapper]: 0.0  (LoggingCache.java:62) 
DEBUG 05-20 12:51:52,805 ==>  Preparing: select eid id,ename name,email,gender from emp where eid= ?   (BaseJdbcLogger.java:145) 
DEBUG 05-20 12:51:52,871 ==> Parameters: 7(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 05-20 12:51:52,940 <==      Total: 1  (BaseJdbcLogger.java:145) 
Emp [eid=7, ename=jane, email=jane.com, gender=, dept=null]
DEBUG 05-20 12:51:52,960 Cache Hit Ratio [bean.EmpMapper]: 0.5  (LoggingCache.java:62) 
Emp [eid=7, ename=jane, email=jane.com, gender=, dept=null]

缓存原理

原理示意图
在这里插入图片描述

实现
在这里插入图片描述

执行顺序
缓存的顺序:二级缓存----->一级缓存------>数据库

mybatis整合ehcache

首先需要导入三个包
ehcache需要的jar包
ehcache-core-2.6.8.jar
ehcache允许需要的日志包
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.2.jar
有着三个包后我们就可以写自己的实现类,实现Cache接口就行
但是自己写实现类好麻烦呀,它是一个成熟的项目,应该自己写实现的
所以mybatis就帮你写好了,官网的git那里有,下载好后导入相应的jar包
mybatis-ehcache-1.0.3.jar
根据官方文档说明,它需要在映射文件配置好,还有需要一个ehcache.xml文件就可以使用ehcache了
EmpMapper映射文件配置

<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="E:\new Java\STSworkspace\TempData\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="1000" 
   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(先进先出)
 -->

这样就可以使用ehcache的缓存了
也可以使用引用缓存
namespace就是你要引用哪个映射文件的命名空间的缓存机制

<cache-ref namespace="bean.EmpMapper"/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReflectMirroring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值