@Cacheable的使用

一、配置

1.配置redis

默认是有配置redis的情况会使用redis作为缓存。

2.配置Cache

@Configuration
// 使用redis作为cache的缓存,前提是要配置redis
@ConditionalOnBean(RedisConfiguration.class)
public class CacheConfiguration {

    @Resource
    private RedisConnectionFactory factory;

    @Resource
    private RedisCacheProperties redisCacheProperties;

    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

    @Bean
    public CacheResolver cacheResolver() {
        return new SimpleCacheResolver(cacheManager());
    }

    @Bean
    public CacheErrorHandler errorHandler() {
        // 用于捕获从Cache中进行CRUD时的异常的回调处理器。
        return new SimpleCacheErrorHandler();
    }

    @Bean
    public CacheManager cacheManager() {
        final Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        //POJO无public的属性或方法时,不报错
        om.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        // null值字段不显示
        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 序列化JSON串时,在值上打印出对象类型
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        // 解决jackson2无法反序列化LocalDateTime的问题
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                // 过期时间
                .entryTtl(Duration.ofMillis(redisCacheProperties.getExpireDefaultMillis()))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        final RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(factory)
                .cacheDefaults(config);

        // 为每个key配置不同的过期时间
        final Map<String, Long> expireMap = redisCacheProperties.getExpireMapMillis();
        if (CollUtil.isNotEmpty(expireMap)) {
            final ConcurrentHashMap<String, RedisCacheConfiguration> configMap = new ConcurrentHashMap<>();
            final Set<String> cacheNames = expireMap.keySet();
            expireMap.entrySet().forEach(e ->
                    configMap.put(e.getKey(), config.entryTtl(Duration.ofMillis(e.getValue())))
            );
            builder.initialCacheNames(cacheNames)
                    .withInitialCacheConfigurations(configMap);
        }

        return builder.build();
    }
}

需要用到的配置类:

@Getter
@Setter
@NoArgsConstructor
@Component
@ConfigurationProperties(prefix = "redis-cache")
public class RedisCacheProperties {

    /**
     * 缓存默认过期时间,单位毫秒
     */
    private long expireDefaultMillis = 86400000;

    /**
     * 缓存针对不同的key设置不同过期时间,单位毫秒
     */
    private Map<String, Long> expireMapMillis;
}

yaml对应的配置:

##cache缓存设置
redis-cache:
  # 默认超时时间,单位毫秒
  expire-default-millis: 86400000
  # 自定义超时时间map,单位毫秒
  expire-map-millis:
    mapTestCache: 6000

3.将Cache配置放入starter

将这些配置放入新的maven工程里面(即starter工程),如果需要此功能只需要引入这个starter工程即可。

starter工程中增加如下两个文件:

  • 增加注解定义,在项目的启动类中增加此注解即可扫描到starter工程的包,并注入到spring:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RootConfiguration.class)
public @interface EnableXXConfiguration {
}
  • 增加类即上面的@Import(RootConfiguration.class),并增加包的扫描位置:
@Configuration
@ComponentScan("com.xx.xxx")
public class RootConfiguration {
}

二、使用

使用前启动类需要加注解:@EnableCaching

使用注解:

  • @Cacheable:触发缓存写入。
  • @CacheEvict:触发缓存清除。
  • @CachePut:更新缓存(不会影响到方法的运行)。
  • @Caching:重新组合要应用于方法的多个缓存操作。
  • @CacheConfig:设置类级别上共享的一些常见缓存设置。

示例代码:

@Service
@Slf4j
public class CacheTestService {

    @Cacheable(cacheNames = "mapTestCache", key = "#mapId")
    public MapEntity findMapEntity(String mapId) {
        log.info("进入数据库查询。。。");
        return new MapEntity()
                .setMapName("测试地图cache")
                .setMapDescription("")
                .setDel(1)
                .setUpdateTime(System.currentTimeMillis());
    }

    @CachePut(cacheNames = "mapTestCache", key = "#map.mapId")
    public MapEntity updateEntity(MapEntity map) {
        log.info("进入数据库更新。。。");
        return map;
    }

    @CacheEvict(cacheNames = "mapTestCache", key = "#mapId")
    public void deleteEntity(String mapId) {
        log.info("进入数据库删除。。。");
    }

}

测试:

    @Test
    public void testCacheFind() {
        final MapEntity mapEntity = cacheTestService.findMapEntity("110");
        log.info("查出来数据:{}", JSONUtil.toJsonStr(mapEntity));
        Assert.assertTrue(true);
    }

    @Test
    public void testCacheUpdate() {
        final MapEntity mapEntity = new MapEntity().setMapName("test更新。。").setMapId("110");
        cacheTestService.updateEntity(mapEntity);
        Assert.assertTrue(true);
    }

    @Test
    public void testCacheDelete() {
        cacheTestService.deleteEntity("110");
        Assert.assertTrue(true);
    }

三、Spring-Cache的不足

1)读模式

  • 缓存穿透:查询一个null数据。解决:缓存空数据:cache-null-values=true;
  • 缓存击穿:大量并发进来同时查询一个正好过期的数据。解决:加锁,sync=true,只有@Cacheable有;
  • 缓存雪崩:大量的key同时过期。解决:加随机时间。

2)写模式

如何保证缓存数据库一致性:

  • 读写加锁,有序进行;(写少的情况,不然一直在等待)
  • 引入canal,感知到MySQL的更新去更新数据库;
  • 读多写多,直接去数据库查询就行;

总结

  • 常规数据(读多写少,即时性,一致性要求不高的数据):完全可以使用Spring-Cache;写模式(只要缓存的数据有过期时间就足够)
  • 特殊数据:特殊设计;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: @CacheableSpring框架提供的一个注解,用于将对应的方法的返回结果存储在缓存中,以便下次请求时直接从缓存中获取结果,提高系统性能。 使用Redis作为缓存提供商,可以通过配置Redis作为Cache Manager来实现@Cacheable使用Redis。下面是具体的步骤: 1. 引入依赖:在项目的pom.xml文件中添加Spring框架的相关依赖和Redis的客户端依赖,如spring-boot-starter-data-redis等。 2. 配置Redis:在项目的配置文件中设置Redis的连接信息,包括host、port、password等。可以通过application.properties或application.yml文件进行配置。 3. 创建Redis连接工厂:使用Redis连接信息创建一个Redis连接工厂Bean,用于创建Redis连接。 4. 创建Cache Manager:使用Redis连接工厂创建一个Cache Manager Bean,该Cache Manager将使用Redis作为缓存提供商。 5. 配置@Cacheable注解:在需要使用缓存的方法上添加@Cacheable注解,并指定缓存的名称,如@Cacheable(value = "userCache")。该注解还可以指定缓存的key,以便根据不同的参数生成不同的缓存key。 6. 运行项目:启动项目后,当使用@Cacheable注解修饰的方法被调用时,系统会先检查缓存中是否存在对应的结果。如果存在,则从缓存中获取结果并返回;如果不存在,则调用方法,然后将方法的返回结果存储在缓存中,以供后续使用。 通过以上步骤,可以让@Cacheable注解使用Redis作为缓存提供商,提高系统的性能和响应速度。同时,使用Redis作为缓存存储,还可以实现分布式缓存,增加系统的可扩展性和稳定性。 ### 回答2: @CacheableSpring框架提供的一个注解,用于为方法添加缓存功能。当方法被调用时,如果缓存中存在相应的缓存结果,则直接从缓存中获取,而不会执行方法。如果缓存中不存在相应的缓存结果,则执行方法,并将方法的返回结果存入缓存中,以备后续使用。 当@CacheableRedis结合使用时,可以将返回结果以键值对的形式存储在Redis缓存服务器中。Redis是一种内存数据库,具有快速读写的特点。通过使用Redis作为缓存服务器,可以提高缓存的读写性能。 使用@Cacheable注解时,需配置Redis作为缓存存储的方式。可以通过在Spring的配置文件中指定Redis相关的属性,比如Redis的连接信息、缓存的过期时间等。 在方法被调用时,@Cacheable会先检查Redis中是否存在相应的缓存结果。如果存在,则直接从Redis中读取缓存结果并返回。如果不存在,则执行方法,并将方法的返回结果存储在Redis中,以备后续使用使用Redis作为缓存服务器,可以解决传统基于内存的缓存机制的性能瓶颈问题。由于Redis缓存数据存储在内存中,读写速度快,能够极大地提高应用程序的性能。 综上所述,通过将@CacheableRedis结合使用,可以实现高效的缓存机制,提高系统的响应速度和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值