-
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
配置使用redis作为缓存
spring: cache: type: redis redis: # 存活时间/过期时间:60s time-to-live: 60000 # 缓存中的key前缀.如果指定了前缀就用我们指定的前缀,如果没有就默认使用缓存的名字作为前缀 key-prefix: CACHE_ # 是否使用key前缀 use-key-prefix: true # 是否缓存空值,防止缓存穿透 cache-null-values: true
-
springCache缓存相关注解
- @Cacheable: 触发将数据保存到缓存的操作
如果缓存中有该注解标识方法的返回结果,则不会调用;否则将方法的结果放入缓存 - @CacheEvict: 触发将数据从缓存删除的操作
- @CacheEvict(value = “category”, allEntries = true)指定删除category分区下的所有数据
- @CachePut: 不影响方法执行更新缓存(可以应用于双写模式:更新数据库的同时将方法的返回值用于更新缓存)
- @Caching: 组合以上多个操作
- @CacheConfig: 在类级别共享缓存的相同配置
- @Caching: 同时进行多种缓存操作,比如同时删除多个缓存
-
自定义redis cache配置类(包括开启缓存功能: @EnableCaching)
package com.kenai.gulimall.product.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @EnableConfigurationProperties(CacheProperties.class) @Configuration @EnableCaching public class MyCacheConfig { @Autowired private CacheProperties cacheProperties; /** * 不使用上面的自动注入,在方法的参数中加上CacheProperties cacheProperties也可以 * @return */ @Bean public RedisCacheConfiguration redisCacheConfiguration(){ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 指定key的序列化方式:string的UTF-8编码 // 指定value的序列化方式为json。这样在redis缓存中便可以看到json的格式 config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); CacheProperties.Redis redisProperties = cacheProperties.getRedis(); // 将配置文件中的配置生效 if(redisProperties.getTimeToLive() != null){ config = config.entryTtl(redisProperties.getTimeToLive()); } if(redisProperties.getKeyPrefix() != null){ config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } if(!redisProperties.isCacheNullValues()){ config = config.disableCachingNullValues(); } if(!redisProperties.isUseKeyPrefix()){ config = config.disableKeyPrefix(); } return config; } }
-
@Cacheable注解的使用
@Override // 注解中value对应的category表示缓存要放入的分区(按照业务类型分) // 如果该方法的返回结果没有放入缓存,则会将缓存放入category分区中,否则不进行操作 // key默认自动生成,也可以指定,接收一个SPEL(spring表达式语言) @Cacheable(value = { "category"}, key = "'level1Categorys'") public List<CategoryEntity> getLevel1Categorys() { log.info("调用getLevel1Categorys方法"); List<CategoryEntity> categoryEntities = this.baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0)); return categoryEntities; }
-
redis中缓存数据展示
虽然格式不太友好,但是可以看出是json格式 -
@CacheEvict注解的使用
/** * 级连更新所有关联数据 * @param category */ // 当更新数据库时,会删除redis缓存中的数据,当下次查询时再进行缓存 @CacheEvict(value = "category", key = "'level1Categorys'") @Override @Transactional public void updateCascade(CategoryEntity category) { this.updateById(category); if(!StringUtils.isEmpty(category.getName())){ categoryBrandRelationService.updateCategory(category.getCatId(), category.getName()); } }
-
springCache总结
- @Cacheable的sync=true的时候,多个线程尝试用相同的key去缓存拿数据的时候,会是一个同步的操作(本质上使用了本地锁synchornized),可以解决缓存击穿的问题(大量并发进来同时查询一个正好过期的数据).
- 其他时候,比如在缓存数据和删除缓存的时候并没有使用锁机制.
- 总结1: 对于常规数据(读多写少,即时性、一致性要求不高的数据),完全可以使用springCache
- 总结2: 对于特殊数据,特殊设计