美文网首页spring 整合使用
SpringCache+Redis缓存

SpringCache+Redis缓存

作者: JBryan | 来源:发表于2021-01-26 19:26 被阅读0次

1、添加依赖

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.4.1</version>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.13.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.4.1</version>
        </dependency>

2、添加配置

application.yml

spring:
  redis:
    host: 192.168.43.129
    port: 6379
  cache:
    type: redis

application类添加@EnableCaching开启缓存注解

@EnableCaching
@SpringBootApplication
public class ApplicationManagementApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationManagementApplication.class, args);
    }

}

3、使用SpringCache

3.1、@Cacheable保存数据

如果缓存中有,则直接返回缓存数据,如果缓存中没有,执行方法体,将方法返回值存入缓存

     /**
     *Cacheable:保存缓存,如果缓存中有,则直接返回缓存数据,如果缓存中没有,执行方法体,
     *           将方法返回值存入缓存
     *testCache: 缓存的名字
     */
    @Cacheable(value = "testCache")
    @RequestMapping("test_cacheable")
    public String testCacheable(){
        return "cacheable";
    }

Redis中缓存结果

  1. key:testCache::SimpleKey []。缓存的名字+::+自动生成的key值
  2. value:\xAC\xED\x00\x05t\x00\x09cacheable。默认使用JDK序列化后的数据。
  3. TTL:-1。默认永不过期


    Cache1.jpg

自定义缓存规则

  1. 指定缓存生成的key:key属性,接收一个SpEL表达式。key = "#id"使用参数id作为key
    @Cacheable(value = "testCache",key = "#id")
    @RequestMapping("test_cacheable")
    public String testCacheable(Integer id){
        System.out.println("进入方法体");
        return "cacheable"+id;
    }
  1. 指定缓存过期时间:application.yml中指定spring.cache.redis.time-to-live,以ms为单位
spring:
  redis:
    host: 192.168.43.129
    port: 6379
  cache:
    type: redis
    redis:
      time-to-live: 3600000

访问http://localhost:8080/test_cacheable?id=1,redis中缓存结果:key为缓存名字+::+参数id的值,并且TTL过期时间为1个小时。

Cache2.jpg
  1. 将数据保存为Json格式:
    为了效果更加明显,让接口返回一个对象,在controller中新建内部类user
    @Cacheable(value = "testCache",key = "#id")
    @RequestMapping("test_cacheable")
    public User testCacheable(Integer id){
        System.out.println("进入方法体");
        User user = new User();
        user.setName("Jessie");
        user.setAge(18);
        return user;
    }

    @Data
    class User{
        String name;
        int age;
    }

新建缓存配置类MyCacheConfig,配置类会让之前yml文件中的配置失效,因此需要把之前配置文件中TTL的配置,在配置类中重新配置一遍。

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;

import java.time.Duration;


/**
 * @author zbw
 */

@Configuration
public class MyCacheConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(){
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
        //默认开启缓存空值,可以防止缓存穿透
        //序列化key的方式
        defaultCacheConfig = defaultCacheConfig
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        //序列化value的方式
        defaultCacheConfig = defaultCacheConfig
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        //每次设置配置值,都会重置其他配置为默认值,因此需要重新指定TTL
        defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofHours(1));

        return defaultCacheConfig;
    }
}

访问:http://localhost:8080/test_cacheable?id=1,Redis中缓存结果:

Cache3.jpg
3.2、@CacheEvict清除缓存

CacheEvict失效模式:执行完方法体之后,将缓存删除,等待下一次执行@Cacheable标注的方法时,再将缓存存入Redis中。

    @CacheEvict(value = "testCache",key = "#id")
    @RequestMapping("update_cacheable")
    public String updateCacheable(Integer id){
        return "Hello CacheEvict";
    }
3.3、@CachePut修改缓存

CachePut双写模式:执行完方法体之后,修改缓存中的数据为方法的返回值。

    @CachePut(value = "testCache",key = "#id")
    @RequestMapping("put_cacheable")
    public User putCacheable(Integer id){
        System.out.println("进入方法体");
        User user = new User();
        user.setName("Jessie");
        user.setAge(20);
        return user;
    }
3.4、@Caching整合多个缓存操作

如果在一个方法里面,需要清除多个缓存,可以使用@Caching,将多条@CacheEvict语句整合在一起。

    @Caching(evict = {
            @CacheEvict(value = "testCache",key = "'1'"),
            @CacheEvict(value = "testCache",key = "'2'")
    })
    @RequestMapping("caching")
    public String caching(){
        return "Hello Caching";
    }

4、使用SpringCache注意事项

从以下几点分析:

  1. 缓存穿透,可以通过缓存空值(cache-null-value=true)解决,默认也是缓存空值的。
  2. 缓存击穿,大量并发查询一条正好过期的数据时,默认是没有加锁,直接访问数据库的,因此无法解决击穿问题。可以通过添加sync=true,使得读取操作加锁执行。
    @Cacheable(value = "testCache",key = "#id",sync = true)
    @RequestMapping("test_cacheable")
    public User testCacheable(Integer id){
        System.out.println("进入方法体");
        User user = new User();
        user.setName("Jessie");
        user.setAge(18);
        return user;
    }
  1. 缓存雪崩,通过给缓存设置同一过期时间来解决,并不一定都是同一时刻触发保存缓存的操作,缓存过期的时间一般也比较分散。
  2. 所有的写模式都没有加锁

总结:对于读多写少、即时性、一致性要求没那么高的场景,完全可以使用SpringCache。但是对于特殊数据需要特殊处理。

相关文章

网友评论

    本文标题:SpringCache+Redis缓存

    本文链接:https://www.haomeiwen.com/subject/skjgzktx.html