几个概念
Cahce:缓存接口,定义缓存操作。实现的有RedisCache、EhCache、ConcurrentMapCache等;
CacheManager:缓存管理器,管理各种缓存组件,默认使用ConcurrentMapCacheManager;
@Cacheable:主要加在方法上,能够缓存方法的返回结果(方法的结果缓存后,下一次调用该方法将不执行,直接从缓存中获取同一对象 );
value:缓存组件名,将结果放在哪个缓存中,可多个
key:缓存数据的key,默认使用方法参数的值,可指定spel表达式
keyGenerator:指定自定义的key生成器
condition:满足条件的可缓存
unless:为true时不缓存
cacheManager:指定缓存管理器。
@CacheEvict:清除缓存;
allEntries:true清除全部,false不清除全部
beforeInvocation:是否在方法执行之前清除缓存,针对方法执行过程中出现异常
@Cacheput:保证方法被调用,而且缓存方法的返回结果;
key要与@Cacheable中指定的key一样才能防止@Cacheable方法再次调用执行,而且指定的CacheManager要相同。
@Caching:定义复杂的缓存规则;
@EableCaching:主配置类上,开启基于注解的缓存;
@CacheConfig:在类上,抽取缓存公共配置,指定缓存组件:cacheNames(可多个),指定cacheManager,指定key的生成器:keyGenerator
KeyGenerator:缓存数据时,key的生成策略;
serialize:缓存数据时,value的序列化策略。
基于注解的ConcurrentMapCache
在未引入其他缓存依赖的情况下,springboot默认使用ConcurrentMapCache,使用注解时的CacheManager为必须,默认为ConcurrentMapCacheManager。
注解中能使用的cache表达式:
自定义缓存key生成器 keyGenerator:
@Configuration
public class TestConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new BasicDataSource();
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
// 方法名,传入参数
public Object generate(Object o, Method method, Object... objects) {
return method.getName() + Arrays.asList(objects);
}
};
}
}
使用:
@CacheConfig(cacheNames = "xzqh")// 指定使用xzqh名字的缓存组件
@Service
public class TestService {
@Autowired
TestMapper testMapper;
@Cacheable(key = "#root.args[0]",cacheManager = "concurrentMapCacheManager")// 指定使用的缓存管理器,key的生成策略
public Object query(String qhbm){
System.out.println("查询:"+qhbm);
Xzqh xzqh = testMapper.getXzqh(qhbm);
return xzqh;
}
// 使用指定的key生成器
@Cacheable(keyGenerator = "keyGenerator")
public Xzqh add(Xzqh xzqh){
testMapper.add(xzqh);
return xzqh;
}
@CachePut(key = "#root.args[0].qhbm")
public Xzqh update(Xzqh xzqh){
System.out.println("修改:1231231"+xzqh.getQhbm());
testMapper.update(xzqh);
return xzqh;
}
@CacheEvict(key = "#root.args[0]",allEntries = false)
public void delete(String qhbm){
System.out.println("删除:"+qhbm);
testMapper.delete(qhbm);
}
@Caching(cacheable = {@Cacheable(key = "#pqhbm")},put = {@CachePut(key = "#result.qhbm"),@CachePut(key = "#result.qhjb")})
public Xzqh getByPqhbm(String pqhbm){
System.out.println("查询父编码:"+pqhbm);
return testMapper.queryByPqhbm(pqhbm);
}
}
单独使用Redis
1. 引入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
底层还是Jedis!
2. 配置redis连接
spring.redis.host=101.297.0.51
spring.redis.port=8888
3. 使用StringRedisTemplate或者RedisTemplate操作缓存
StringRedisTemplate针对操作字符串,RedisTemplate能操作各种数据类型,存储对象必须实现序列化接口,否则报错,而默认使用的是JDK序列化方式,这种序列化存储的结果是一串阅读不友好的字符,改使用json的序列化方式。
springboot 2.x后的序列化方式:
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
//连接工厂
template.setConnectionFactory(redisConnectionFactory);
// 序列化配置 解析任意对象
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// json序列化利用ObjectMapper进行转义
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //指定要序列化的域,filed,get和set、Any是包括private// 和public
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//
jackson2JsonRedisSerializer.setObjectMapper(om);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
// 2.序列化String类型
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
return template;
}
使用RedisTemplate:
@Service
public class TestService {
@Autowired
TestMapper testMapper;
@Autowired
RedisTemplate redisTemplate;
public Xzqh query1(String qhbm){
System.out.println("查询1:"+qhbm);
Xzqh xzqh = testMapper.getXzqh(qhbm);
redisTemplate.opsForHash().put("tem",qhbm,xzqh);
redisTemplate.opsForValue().set("killo","2000公里");
return xzqh;
}
public Xzqh query2(String qhbm){
System.out.println("查询2:"+qhbm);
Xzqh xzqh = testMapper.getXzqh(qhbm);
redisTemplate.opsForHash().put("tem",qhbm,xzqh);
Xzqh tem = (Xzqh) redisTemplate.opsForHash().get("tem", qhbm);
System.out.println(tem.toString());
return xzqh;
}
}
基于注解的RedisCache
缓存自动配置类:CacheAutoConfiguration,默认使用SimpleCacheConfiguration产生ConcurrentMapCacheManager,引入redis依赖后,将使用RedisCacheConfiguration产生RedisCacheManager。
注解方式需要有CacheManager,CacheManager调用缓存操作工具执行缓存操作。
所以需要自定义配置RedisCacheManager和RedisTemplate(json序列化),也可使用默认的。
@Configuration
public class TestConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new BasicDataSource();
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
return method.getName() + Arrays.asList(objects);
}
};
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
//连接工厂
template.setConnectionFactory(redisConnectionFactory);
// 序列化配置 解析任意对象
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// json序列化利用ObjectMapper进行转义
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //指定要序列化的域,filed,get和set、Any是包括private// 和public
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//
jackson2JsonRedisSerializer.setObjectMapper(om);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
// 2.序列化String类型
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
return template;
}
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
RedisCacheManager redisCacheManager =
RedisCacheManager.builder(factory)
.cacheDefaults(defaultCacheConfig(10000))
.transactionAware()
.build();
return redisCacheManager;
}
private RedisCacheConfiguration defaultCacheConfig(Integer second) {
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(second))
.serializeKeysWith(RedisSerializationContext
.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(serializer))
.disableCachingNullValues();
return config;
}
}
CacheManager和RedisTemplate可同时使用:
@CacheConfig(cacheNames = "xzqh")
@Service
public class TestService {
@Autowired
TestMapper testMapper;
@Autowired
RedisTemplate redisTemplate;
public Xzqh query1(String qhbm){
System.out.println("查询1:"+qhbm);
Xzqh xzqh = testMapper.getXzqh(qhbm);
redisTemplate.opsForHash().put("tem",qhbm,xzqh);
redisTemplate.opsForValue().set("killo","2000公里");
return xzqh;
}
public Xzqh query2(String qhbm){
System.out.println("查询2:"+qhbm);
Xzqh xzqh = testMapper.getXzqh(qhbm);
redisTemplate.opsForHash().put("tem",qhbm,xzqh);
Xzqh tem = (Xzqh) redisTemplate.opsForHash().get("tem", qhbm);
System.out.println(tem.toString());
return xzqh;
}
/**
* 之所以使用Object而不使用对应的实体接收,是因为从缓存中读取已存在的数据不能够自动转化成对应的实体
* @param qhbm
* @return
*/
@Cacheable(key = "#root.args[0]",cacheManager = "redisCacheManager")
public Object query(String qhbm){
System.out.println("查询:"+qhbm);
Xzqh xzqh = testMapper.getXzqh(qhbm);
return xzqh;
}
public void add(Xzqh xzqh){
testMapper.add(xzqh);
}
@CachePut(key = "#root.args[0].qhbm")
public Xzqh update(Xzqh xzqh){
System.out.println("修改:1231231"+xzqh.getQhbm());
testMapper.update(xzqh);
return xzqh;
}
@CacheEvict(key = "#root.args[0]",allEntries = false)
public void delete(String qhbm){
System.out.println("删除:"+qhbm);
testMapper.delete(qhbm);
}
@Caching(cacheable = {@Cacheable(key = "#pqhbm")},put = {@CachePut(key = "#result.qhbm"),@CachePut(key = "#result.qhjb")})
public Xzqh getByPqhbm(String pqhbm){
System.out.println("查询父编码:"+pqhbm);
return testMapper.queryByPqhbm(pqhbm);
}
}
之所以使用Object而不使用对应的实体接收,是因为从缓存中读取已存在的数据不能够自动转化成对应的实体。