キャッシュ宣言の場合、Springのキャッシュ抽象化は一連のJavaアノテーションを提供します
@Cacheable:キャッシュ
ポピュレーションをトリガーします:キャッシュにデータを保存する操作をトリガーします@CacheEvict:キャッシュエビクションをトリガーします
:キャッシュからデータを削除する操作をトリガーします@CachePut:更新メソッドの実行に干渉しないキャッシュ
:メソッドの実行に影響を与えませんupdate cache @Caching:メソッドに適用される複数のキャッシュ操作を再グループ化します:上記の複数の操作を組み合わせます
@CacheConfig:クラスレベルでいくつかの一般的なキャッシュ関連設定を共有します:クラスレベルで共有キャッシュの同じ構成
1.mavenを導入します
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!-- Lettuce的bug导致netty堆外内存溢出 切换使用jedis-->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Lettuce的bug导致netty堆外内存溢出 切换使用jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- 整合SringCache 简化缓存开发-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.application.propertiesに構成情報を追加します
#以下是整合Spring Cache 的相关配置
#配置缓存的类型 (最简化的配置)
spring.cache.type=redis
#指定缓存的名字
#spring.cache.cache-names=qq,
#指定缓存的存活时间 单位:ms
spring.cache.redis.time-to-live=3600000
#为了区分redis其他的东西
#如果指定了前缀,就用我们指定的前缀,如果没有就默认使用缓存的名字(分区名-value)作为前缀
#优先级高
#spring.cache.redis.key-prefix=CACHE_
#默认是使用前缀的
spring.cache.redis.use-key-prefix=true
#是否缓存空值 防止缓存穿透
spring.cache.redis.cache-null-values=true
3.構成クラスを追加します
//绑定配置文件的配置
@EnableConfigurationProperties(CacheProperties.class)
//开启缓存功能
@EnableCaching
@Configuration
public class MyCacheConfig {
// @Autowired
// CacheProperties cacheProperties;
/**
* 没有用上配置文件中的东西
* 1)、原来配置文件的绑定配置是这样子的
* @ConfigurationProperties(prefix = "spring.cache")
* public class CacheProperties {
* 2)、要让他生效
* @EnableConfigurationProperties(CacheProperties.class)
* @return
*/
@Bean
RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// config = config.entryTtl();
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;
}
}
4.クエリテストの作成:キャッシュの侵入とキャッシュの故障を防ぐように構成されています
/**
* 1、每一个需要缓存的数据我们都需要指定放到那个名字的缓存【缓存分区的划分【按照业务类型划分】】
* 2、@Cacheable({"category"})
* 代表当前方法的结果需要缓存,如果缓存中有,方法不调用
* 如果缓存中没有,调用方法,最后将方法的结果放入缓存
* 3、默认行为:
* 1、如果缓存中有,方法不用调用
* 2、key默自动生成,缓存的名字:SimpleKey[](自动生成的key值)
* 3、缓存中value的值,默认使用jdk序列化,将序列化后的数据存到redis
* 3、默认的过期时间,-1
*
* 自定义操作
* 1、指定缓存使用的key key属性指定,接收一个SpEl
* 2、指定缓存数据的存活时间 配置文件中修改ttl
* 3、将数据保存为json格式
* 4、Spring-Cache的不足:
* 1、读模式:
* 缓存穿透:查询一个null数据,解决 缓存空数据:ache-null-values=true
* 缓存击穿:大量并发进来同时查询一个正好过期的数据,解决:加锁 ? 默认是无加锁
* 缓存雪崩:大量的key同时过期,解决:加上随机时间,Spring-cache-redis-time-to-live
* 2、写模式:(缓存与数据库库不一致)
* 1、读写加锁
* 2、引入canal,感知到MySQL的更新去更新数据库
* 3、读多写多,直接去数据库查询就行
*
* 总结:
* 常规数据(读多写少,即时性,一致性要求不高的数据)完全可以使用SpringCache 写模式( 只要缓存数据有过期时间就足够了)
*
* 特殊数据:特殊设计
* 原理:
* CacheManager(RedisManager) -> Cache(RedisCache) ->Cache负责缓存的读写
* sync = true解决缓存击穿 默认是false
*/
@Cacheable(value = {
"category"}, key = "#root.method.name", sync = true)
@Override
public List<CategoryEntity> getLevel1Catrgorys() {
//测试spring cache
System.out.println("public List<CategoryEntity> getLevel1Catrgorys() {....");
//压力测试 数据库navicat增加了 parent_cid 为索引
// long l = System.currentTimeMillis();
List<CategoryEntity> categoryEntities = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
// System.out.println("消耗时间->:" + (System.currentTimeMillis()-l) + "ms");
return categoryEntities;
// return null;//测试缓存空值
}
データを変更または削除するときにキャッシュを削除する必要がある場合はどうなりますか?
5.キャッシュ削除テストを作成します。
カテゴリパーティション内のすべてのデータを削除します。次のアノテーションを使用してキャッシュを削除することもできます。
@Caching(evict = {
@CacheEvict(value = "category", key = "'getLevel1Catrgorys'"),
@CacheEvict(value = "category", key = "'getCatalogJson'")
})
キャッシュされた複数の値を削除します。
//存储同一类型的数据,都可以指定成同一个分区 分区名默认就是缓存的前缀
//失效模式 删除category区下【所有】的数据
@CacheEvict(value = "category", allEntries = true)
//同时进行多种缓存操作 组合删除
// @Caching(evict = {
// //失效模式:修改删除缓存
// @CacheEvict(value = "category", key = "'getLevel1Catrgorys'"),
// @CacheEvict(value = "category", key = "'getCatalogJson'")
// })
//双写模式 修改后再放入缓存
// @CachePut
@Transactional
//级联更新 所有数据
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
//同时修改缓存中的数据
//redis.del(catalogJSON);等待下次主动查询进行更新
}