EhCache是一个比较成熟的Java缓存框架,最早从hibernate发展而来,是进程中的缓存 系统,它提供了用内存,磁盘文件存储,以及分布式存储方式等多种灵活的cache管理方案,快速简单。
Spring Boot对Ehcache的使用提供支持,所以在Spring Boot中只需简单配置即可使用Ehcache实现数据缓存处理。
一、Spring Cache相关注解说明
SpringBoot缓存实现内部使用SpringCache实现缓存控制,这里集成Ehcache实际上是对SpringCache抽象的其中-种实现,这里在使用Ehcache实现缓存控制时相关注解说明如下:
1、@CacheConfig
用于标注在类上,可以存放该类中所有缓存的公有属性,比如设置缓存的名字。
@CacheConfig( cacheNames ="users")
public interface UserService {.....}
配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。
2、 @Cacheable
应用到读取数据的方法.上,即可缓存的方法,如查找方法,先从缓存中读取,如果没有再调用相应方法获取数据,然后把数
据添加到缓存中。
该注解主要有下面几个参数:
●value、 cacheNames :两个等同的参数( cacheNames为Spring4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring了中原本必须有的value属性,也成为非必需项了。
●key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如: @Cacheable(key = “#p0”) :使用函数第一个 参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档。
●condition :缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = “#p0”, condition = “#p0.length()< 3”),表示只有当第一个 参数的长度小于3的时候才会被缓存。
●unless :另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
●keyGenerator :用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现
org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是: 该参数与key是互斥的。
●cacheManager :用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
●cacheResolver :用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。
@Cacheable(value = “user" ,key=“#id")
User selectUserById(final Integer id);
3、@CachePut
应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存,@CachePut 的参数与@Cacheable类似,示例如下:
@CachePut(value = "user", key = " #user.id")
public User save(User user) {
users. add(user);
return user;
}
4、@CacheEvict
应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据,示例如下:
@CacheEvict(value = "user", key = "#id")
void delete(final Integer id);
除了同@Cacheable一样的参数之外, @CacheEvict 还有下面两个参数:
●allEntries :非必需,默认为false。当为true时,会移除所有数据
●beforelnvocation :非必需,默认为false, 会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。
5、@Caching
组合多个Cache注解使用。示例:
@Caching(
put={
@CachePut(value = "user", key = "#user .id" ),
@Cacheput(value = "user", key = "#user . username"),
@Cachefut(value = "user", key = "#user.age")
}
)
将id -> user ; username -> user ; age -> user进行缓存。
二、配置环境
1、pom.xml依赖添加
<!-- Ehcache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
2、ehcache.xml文件添加
src/main/resources目录下添加ehcache.xml文件,内容如下:
<ehcache name= "mycache">
<!--
如果不使用磁盘存储,只需要将diskStore注释掉即可;
如果使用,需要在ehcache.xml文件中的ehcahce元素下的定义一个diskStore元素并指定其path属性.
-->
<diskStore path="C:\java\cache"/>
<!--
name :缓存名称。
maxElementsInMemory :缓存最大数目
maxElementsOnDisk :硬盘最大缓存个数。
eternal:对象是否永久有效,-但设置了,timeout将不起作用。
overflowToDisk :是否保存到磁盘,当系统宕机时
timeToIdleSeconds :设置对象在失效前的允许闲置时间(单位:秒)。
仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,表示可闲置时间无穷大。
timeToliveSeconds:设置射象在失效前允许存活时间(单位:秒)。
最大时间介于创建时间和失效时间之间。
仅当eternal=false对象不是永久有效时使用,默认是0,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据
Whether the disk store persists between restarts of the Virtual Machine.
The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore (磁盘缓存)的缓存区大小。
默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElements InMemory限制时,会根据指定的策略去清理内存
默认策略是LRU (最近最少使用)。你可以设置为FIFO (先进先出)或是LFU (较少使用)。
clearonFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:
可选策略有:
LRU (最近最少使用,默认策略)
Least Recently Used,最近最少使用的。
FIFO (先进先出)
First in First out, 这个是大家最熟的,先进先出。
LFU(汇最少访问次数)
Less Frequently Used, 就是例子中使用的策略,就是一直以来最少 被使用的。
缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk= "10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
<cache
name="users "
eternal="false"
maxElementsInMemory="100"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy= "LRU"/>
</ehcache>
3、application.yml缓存配置
spring:
datasource:
type: com.mchange.V2.c3p0.ComboPooledDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc :mysql://127.0.0.1:3306/dai_pao?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: 123456
devtools:
restart :
enabled: true
#设置重启的目录,添加目录的文件需要restart
additional-paths: src/main/java
#解决项目自动重新编译后接口报404的问题
poll-interval: 3000
quiet-period: 1000
## Ehcache缓存配置
cache:
ehcache:
config: classpath: ehcache.xml
4、启动缓存
在Starter启动入口类中,添加@EnableCaching注解,启动缓存
@SpringBootApplication
@EnableCaching
@MapperScan("com.xxx.dao")
public class Starter {
public static void main(String[] args) {
SpringAppl ication.run(Starter.class);
}
}
三、缓存实现
这里以UserService的方法为例:
1、用户详情查询缓存
//通过用户ID查询用户信息,添加到缓存
@GetMapping("user/ids/{user_id}")
@Cacheable(value="users",key = "#user_id")
public MyUser queryUserByIds(@PathVariable String user_id){
return userService.queryUserByIds(user_id);
}
2、用户列表查询缓存
@Cacheable(value = "users",key="#userQuery.userName+'-'+#userQuery.pageNum+'-'+#userQuery.pageSize")
public PageInfo<User> queryUserByParams(UserQuery userQuery){
PageHelper.startPage(userQuery.getPageNum(),userQuery.getPageSize());
return new PageInfo<User>(userMapper.selectByParams(userQuery));
}
3、⽤户更新 & 删除缓存
@CacheEvict(value = "users",key="#user.id")
public void updateUser(User user) {
AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()), "⽤户名不能为空!");
AssertUtil.isTrue(StringUtils.isBlank(user.getUserPwd()),"⽤户密码不能为空!");
User temp = userMapper.queryUserByUserName(user.getUserName());
AssertUtil.isTrue(null != temp && !(temp.getId().equals(user.getId())), "该⽤户已存在!");
AssertUtil.isTrue(userMapper.update(user)<1,"⽤户记录添加失败!");
}
@CacheEvict(value = "users",allEntries=true)
public void deleteUser(Integer userId){
AssertUtil.isTrue(null == userId || null == userMapper.queryById(userId),"待删除记录不存在!");
AssertUtil.isTrue(userMapper.delete(userId)<1,"⽤户删除失败!");
}