MyBatis之缓存

现在MyBatis因其灵活性使用率很高,而且MyBatis也提供缓存功能,所以也可了解一下。MyBatis提供一级缓存和二级缓存,一级缓存(同一个sqlSession共享数据)是默认开启的而且不能关闭,二级缓存(不同的sqlSession之间共享数据)是需要配置开启的。

MyBatis之一级缓存

一级缓存是默认开启的,只要是同一个sqlSession,第二次查询就会从缓存中读取数据。不过如果跟Spring集成后,一级缓存就会失效。原因就是MyBatis的一级缓存是需要同一个sqlSession,但是Spring会在sqlSession使用完毕后就会关闭,这样缓存数据将会清空。当第二个请求,重新新建sqlSession,然后又去请求数据库。目前我们一般是跟Spring整合使用,但是因为这个原因只能寻求其二级缓存。

MyBatis之二级缓存

配置

一级缓存无法实现,但是MyBatis提供二级缓存,而且配置比较简单,首先需要返回的POJO类必须可序列化,即要求实现Serializable接口,然后在XML文件中配置<cache />

配置缓存可以使用不同的参数:

<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true" />
  • eviction 代表缓存回收策略,目前MyBatis提供以下回收策略。(1)LRU,最近最少使用的,移除最长时间不用的对象。(2)FIFO,先进先出,按对象进入缓存的顺序来移除他们。(3)SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象。(4)WEAK,弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象。
  • flushInterval 刷新间隔时间,单位为毫秒,如果不配置,那么当SQL被执行的时候才会去刷新缓存。
  • size 引用数目,代表缓存最多可以存储多少对象,不宜设置过大,不然会导致内存溢出。
  • readOnly 只读,意味着缓存数据只能读取而不能修改。
全局/局部配置

全局配置:默认就是true,一般不用配置,配置就是取消二级缓存,意义不大。

<settings>
	<!-- 二级缓存总开关 -->
	<setting name="cacheEnabled" value="false"/>
</settings>

局部配置:使用useCacheflushCache,前者表示是否需要使用缓存,而后者表示插入后是否需要刷新缓存。

<select ... flushCache="false" useCache="true" />
<insert ... flushCache="true" />
<update ... flushCache="true" />
<delete ... flushCache="true" />
使用原则

(1) 多个namespace不要操作同一张表

二级缓存中的数据是基于namespace的,不同的namespace的数据互不干扰,如果某namespace中的进行增删改而造成缓存刷新,只会引起该namespace中的二级缓存数据刷新,不会对其他namespace下的数据有影响,所以从其他namespace中读取的数据还是未更新的。

(2)不要在关联关系表上执行增删改操作

一个namespace一般是同一个表进行操作,若表间存在关联关系,也就意味着同一个表可能出现在多个namespace下,这样就会存在上述讲到的风险。

(3)查询多于修改时使用二级缓存

二级缓存频繁刷新容易降低系统性能。

案例

Department.java

public class Department implements Serializable

DepartmentMapper.xml

 <cache/>

测试

@Test
public void testDepartment(){
	try {
		System.out.println("=================================");
		MvcResult result1=mockMvc.perform(MockMvcRequestBuilders
				.get("/depts"))
		.andReturn();
		MvcResult result2=mockMvc.perform(MockMvcRequestBuilders
				.get("/depts"))
		.andReturn();
	
		System.out.println(result1.getResponse().getContentAsString());
		System.out.println(result2.getResponse().getContentAsString());
		System.out.println("=================================");
	} catch (Exception e) {
		e.printStackTrace();
	}
}

结果

.
.
.
2023-09-01 11:46:44,987 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Creating a new SqlSession
2023-09-01 11:46:45,012 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2063c53e]
2023-09-01 11:46:45,075 [main] DEBUG [com.plf.hello.dao.DepartmentMapper] - Cache Hit Ratio [com.plf.hello.dao.DepartmentMapper]: 0.0
2023-09-01 11:46:45,085 [main] DEBUG [org.mybatis.spring.transaction.SpringManagedTransaction] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5ce4369b] will be managed by Spring
2023-09-01 11:46:45,095 [main] DEBUG [com.plf.hello.dao.DepartmentMapper.selectByExample] - ==>  Preparing: select dept_id, dept_name from tbl_dept 
2023-09-01 11:46:45,149 [main] DEBUG [com.plf.hello.dao.DepartmentMapper.selectByExample] - ==> Parameters: 
2023-09-01 11:46:45,216 [main] DEBUG [com.plf.hello.dao.DepartmentMapper.selectByExample] - <==      Total: 2
2023-09-01 11:46:45,217 [main] DEBUG [com.alibaba.druid.pool.PreparedStatementPool] - {conn-10001, pstmt-20000} enter cache
2023-09-01 11:46:45,218 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2063c53e]
2023-09-01 11:46:45,218 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2063c53e]
2023-09-01 11:46:45,301 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2063c53e]
2023-09-01 11:46:45,301 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2063c53e]
2023-09-01 11:46:45,301 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Initiating transaction commit
2023-09-01 11:46:45,301 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5ce4369b]
2023-09-01 11:46:45,306 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5ce4369b] after transaction
.
.
.
2023-09-01 11:46:45,493 [main] DEBUG [com.plf.hello.dao.DepartmentMapper] - Cache Hit Ratio [com.plf.hello.dao.DepartmentMapper]: 0.5
2023-09-01 11:46:45,493 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4248e66b]
2023-09-01 11:46:45,493 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4248e66b]
2023-09-01 11:46:45,493 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4248e66b]
2023-09-01 11:46:45,493 [main] DEBUG [org.mybatis.spring.SqlSessionUtils] - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4248e66b]
2023-09-01 11:46:45,493 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Initiating transaction commit
2023-09-01 11:46:45,493 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5ce4369b]
2023-09-01 11:46:45,497 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5ce4369b] after transaction
.
.
.
{"code":100,"msg":"处理成功","extend":{"depts":[{"deptId":1,"deptName":"技术部"},{"deptId":2,"deptName":"餐饮部"}]}}
{"code":100,"msg":"处理成功","extend":{"depts":[{"deptId":1,"deptName":"技术部"},{"deptId":2,"deptName":"餐饮部"}]}}

上述结果可知使用二级缓存,只请求了一次SQL语句,其中Cache Hit Ratio [com.plf.hello.dao.DepartmentMapper]: 0.5显示缓存命中率0.5。

Ehcache缓存

MyBatis毕竟是用于操作SQL的,在缓存方面肯定不如其他的缓存更实用,目前比较多的就是Ehcache、Redis、MongoDB等用作缓存,这里主要实现Spring+Ehcache的缓存

pom.xml

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.11</version>
</dependency>

ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">  	
<!-- 缓存数据要存放的磁盘地址 -->
<diskStore path="E:\temp\ehcache" />
<!-- 
diskStore:指定数据在磁盘中的存储位置。
defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略 
以下属性是必须的: 
maxElementsInMemory - 在内存中缓存的element的最大数目 
maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大 
eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断 
overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大 
timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 
diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作 
memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) -->

	<defaultCache
	 	maxElementsInMemory="1000" 
	 	maxElementsOnDisk="10000000" 
	 	eternal="false" 
	 	overflowToDisk="false" 
	 	timeToIdleSeconds="120" 
	 	timeToLiveSeconds="120" 
	 	diskExpiryThreadIntervalSeconds="120" 
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
	
	 <cache name="myCache"
        eternal="false" 
	 	overflowToDisk="false" 
	 	timeToIdleSeconds="120" 
	 	timeToLiveSeconds="120" 
	 	diskExpiryThreadIntervalSeconds="120" 
		memoryStoreEvictionPolicy="LRU"/>

</ehcache>

applicationContext.xml

xmlns:cache="http://www.springframework.org/schema/cache"

xsi:schemaLocation="http://www.springframework.org/schema/cache 
http://www.springframework.org/schema/cache/spring-cache-4.3.xsd"


<cache:annotation-driven cache-manager="cacheManager"/>
    
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
	<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
	<property name="cacheManager" ref="ehcacheManager"/>
	<property name="transactionAware" value="true"/>
</bean>

DepartmentService.java

@Cacheable(value = "myCache")
public List<Department> getDepts() {
	return departmentMapper.selectByExample(null);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值