当前位置:   article > 正文

Spring Cache - Redis 的使用 自定义缓存配置_java 配置了spring.cache.redis.time-to-live 在哪里使用

java 配置了spring.cache.redis.time-to-live 在哪里使用

Spring Cache官网:https://docs.spring.io/spring-framework/docs/5.2.11.RELEASE/spring-framework-reference/integration.html#cache

一、使用

1、引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
2、配置
spring:
  # redis配置
  redis:
    host: localhost
    port: 6379
    pool:
      # 连接池最大连接数(使用负值表示没有限制)
      max-active: 8
      # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-wait: -1
      # 连接池中的最大空闲连接
      max-idle: 8
      # 连接池中的最小空闲连接
      min-idle: 0
    # 连接超时时间(毫秒)
    timeout: 0

  # cache配置	
  cache:
    type: redis
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
3、开启缓存功能
@EnableCaching
@SpringBootApplication
public class GulimallProductApplication {
	public static void main(String[] args) {
		SpringApplication.run(GulimallProductApplication.class, args);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
4、测试 @Cacheable
@Cacheable(value={"user"},key = "'userList'")
@GetMapping("/getUserList")
public List<User> getUserList(){
    System.out.println("getUserList....");
    //构造测试数据
    List<User> userList = new ArrayList<>();
    userList.add(new User("张三", 18));
    userList.add(new User("李四", 19));
    userList.add(new User("王五", 20));
    return userList;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

@Cacheable 注解说明

缓存当前方法的返回的结果, 如果缓存中有,不调用方法,直接返回;如果缓存中没有,调用方法,最后将方法的结果放入缓存;

默认行为

  • 缓存的value值,默认使用jdk序列化机制,将序列化的数据存到redis中;

  • key是默认生成的,如果不指定,默认user::SimpleKey [];可以通过key属性指定,接收一个SpEL表达式的值;

  • 默认时间是 -1;可以在配置文件中配置

    # 缓存存活时间,单位:毫秒
    spring.cache.redis.time-to-live=360000
    
    • 1
    • 2

@Cacheable 属性说明

5、访问

访问接口:localhost:8080/list
第一次打印 getUserList....;查看redis缓存数据,redis中已经存入user的数据;
第二次直接走缓存,不调用方法,不打印;

二、自定义缓存配置

缓存中的value默认是用jdk序列化,不方便的我们查看,修改成json序列化;

自定义配置类
@EnableCaching //开启缓存启动类的注解从启动类移到这里
@Configuration
public class MyCacheConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        //key的序列化 string
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        //value的序列化  json
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return config;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

测试(同上),缓存中的value已经用json序列化,但过期时间变成 -1;也就是说配置文件中的值失效了!

[
  "java.util.ArrayList",
  [
    {
      "@class": "com.gulimall.product.entity.User",
      "name": "张三",
      "age": 18
    },
    {
      "@class": "com.gulimall.product.entity.User",
      "name": "李四",
      "age": 19
    },
    {
      "@class": "com.gulimall.product.entity.User",
      "name": "王五",
      "age": 20
    }
  ]
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
配置文件失效问题

原因:源码中缓存配置类CacheProperties并没有放在容器中我们需要开启属性配置绑定功能:@EnableConfigurationProperties(CacheProperties.class),然后拿到配置文件的值赋值到属性中;可以参考源码RedisCacheConfiguration类的createConfiguration方法;

@EnableConfigurationProperties(CacheProperties.class) //开启属性配置绑定功能
@EnableCaching  //开启缓存启动类的注解从启动类移到这里
@Configuration
public class MyCacheConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // config = config.entryTtl();

        //key的序列化 string
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        //value的序列化  json
        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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

拿到容器中的CacheProperties对象,可以像上面一样通过方法参数拿到,也可以通过注入一个属性拿到;

@Autowired
public CacheProperties cacheProperties;
  • 1
  • 2

三、Spring Cache 注解

  • @Cacheable: 将数据保存到缓存;
  • @CacheEvict: 将数据从缓存删除;失效模式
  • @CachePut: 不影响方法执行更新缓存;双写模式
  • @Caching: 组合多个缓存操作;
  • @CacheConfig: 在类级别共享缓存的相同配置;
@Cacheable

添加到缓存

@Cacheable(value={"user"},key = "'userList'")
@GetMapping("/getUserList")
public List<User> getUserList(){
    System.out.println("getUserList....");
    //构造测试数据
    List<User> userList = new ArrayList<>();
    userList.add(new User("张三", 18));
    userList.add(new User("李四", 19));
    userList.add(new User("王五", 20));
    return userList;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
@CacheEvict

删除缓存,【失效模式】

@CacheEvict(value={"user"},key = "'userList'")
@PostMapping("/addUser")
public User addUser(@RequestBody User user){
    System.out.println("addUser....");
    return user;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

删除user分区的所有属性:@CacheEvict(value={"user"}, allEntries = true)

@CachePut

根据返回值更新缓存,【失效模式】

@CachePut(value={"user"}, key = "'userList1'")
@PutMapping("/updateUser")
public List<User> updateUser(){
    System.out.println("updateUser....");
    //构造测试数据
    List<User> userList = new ArrayList<>();
    userList.add(new User("1","张三", 18));
    return userList;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
@Caching

组合多个缓存操作;

//同时删除user::userList1 和user::userList2 缓存
@Caching(evict = {
    @CacheEvict(value={"user"},key = "'userList1'"),
    @CacheEvict(value={"user"},key = "'userList2'")
})
@GetMapping("/caching")
public String caching(){
    System.out.println("caching....");
    return "caching ok";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、Spring-Cache的不足之处

读模式

  • 缓存穿透:查询一个null数据;
    解决方案:缓存空数据;
  • 缓存击穿:大量并发进来同时查询一个正好过期的数据;
    解决方案:默认是无加锁的;使用@Cacheable(sync = true)来解决击穿问题;
  • 缓存雪崩:大量的key同时过期;
    解决方案:加过期时间;

读模式的3个问题spring Cache都考虑到了;

写模式:(缓存与数据库一致)

  • 读写加锁;
  • 引入Canal,感知到MySQL的更新去更新Redis;
  • 读多写多,直接去数据库查询就行;

写模式spring Cache 没做特殊处理,根据特殊业务进行特殊处理!

总结

  • 常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache)
    写模式(只要缓存的数据有过期时间就足够了);
  • 特殊数据:特殊设计。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/389734
推荐阅读
相关标签
  

闽ICP备14008679号