mybatis学习-缓存的使用和理解

本文详细解析MyBatis中的一级缓存和二级缓存工作原理,包括缓存的触发条件、缓存失效场景及如何配置和使用二级缓存,特别关注于如何提升数据库查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理解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(先进先出)
 -->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值