Redis与SpringCache

这涉及两个地方的数据操作,常见方式:

双写模式:在修改数据库数据后,再查一遍数据库,将查到的数据覆盖原有的缓存。

失效模式:在修改数据库数据后,删除缓存数据,等到再查的时候重新放入缓存。

上面两种模式在线程大并发时,都会出现漏洞

例子:双写模式,线程1和线程2同时修改数据库同一条数据,线程1先修改Mysql,但还没来得及修改Redis,线程2进来了,修改Mysql,又修改了Redis,此时线程1才来修改Redis,此时数据就是脏数据。

同理失效模式也会出现类似的问题,假设现在缓存没有数据,但数据库有数据值为1,此时有两个并发线程,线程1将数据库值1修改成2但没有提交,就卡顿一下,Redis没有改,线程2来读数据库值为1,它也卡顿一会,Redis也没有改,这时线程1缓过神提交并修改Redis,数据库的值变成2,缓存也更新成2,好了,现在线程2也要更新缓存,变为1,这时缓存的数据与数据库就不一致了。

解决方案:加分布式读写锁,写时不可以读,读的是时候不可以写,读读共享锁,让操作Mysql与Redis两步操作同步完成,缺点效率会慢。(读写互斥)

缓存的使用原则 (读多写少,实时要求不高);如果数据经常修改操作并且要求数据即时视化,不走缓存,应该直接查数据库。

其它解决方案:

1.基础数据可以使用Mysql的伪从服务器Canal订阅binlog同步修改Redis方式,补充一点Canal还 可以做大数据分析,比如电商里根据浏览记录,推荐兴趣商品;

结论:

1.读多写少的数据可以使用缓存,并加上过期时间,已经能满足大多数场景;

2.放入缓存的数据是实时性不高的,要求实时性高的直接查数据库获取.

SpringCache操作Redis,先走缓存,如果Redis中没有数据,则去Mysql查,并将查到数据放入Redis

一、SpringCache依赖与使用


        <!--SpringCache 操作缓存-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

application.yml 配置文件 (使用Redis做缓存)


spring:  
  redis:
    host: 192.168.126.131
    port: 6379    #默认是6379

application.properties配置文件 (使用SpringCache操作Redis)


spring.cache.type=redis
spring.cache.redis.time-to-live=360000
spring.cache.redis.key-prefix=CACHE_
spring.cache.redis.use-key-prefix=true
#是否缓存空值,防止缓存穿透问题
spring.cache.redis.cache-null-values=true

由于Redis默认使用jdk序列化,为了能看懂和数据通用转成JSON格式,需要自定义反序列化配置


package com.atguigu.gulimall.product.config;

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;

/**
 * User: ldj
 * Date: 2022/9/5
 * Time: 20:23
 * Description: 缓存配置
 */

@EnableCaching
@Configuration
@EnableConfigurationProperties({CacheProperties.class}) //往容器添加Bean
public class MyCacheConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        RedisCacheConfiguration config = RedisCacheConfiguration
                .defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .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;
    }
}

配置完后,主启动类加@EnableCaching开启缓存注解,使用注解就能实现缓存的增删改查


#触发缓存保存
@Cacheable(value = {"数据逻辑分区"}, key = "#root.method.getName()",sync = true} 

#触发缓存移除
@CacheEvict

#不影响方法执行更新缓存
@CachePut

#组合操作缓存
@Caching(evict = {
     @CacheEvict(value = {"数据逻辑分区"}, key = "'key1'"),
     @CacheEvict(value = {"数据逻辑分区"}, key = "'key2'")
      })

#在类级别共享相同的缓存配置
@CacheConfig

二、SpringCache存在问题(面试题)

  1. 缓存穿透:空命中,查缓存和数据库都不存在的数据;

解决:允许存空对象+过期时间。SpringCache可以配置spring.cache.redis.cache-null-values=true

  1. 缓存击穿:热点数据缓存刚好过期,大量并发涌入查数据,压垮数据库;

解决:增大缓存过期时间 或者 双检加锁 [参考链接] SpringCache可以使用注解@Cacheable(value = {"category"}, key = "#root.method.getName()",sync = true)

  1. 缓存雪崩:大量key同时过期或者失效,多出现原因是断电或自然灾难;

解决:加随机时间(不推荐),大系统机房做好容灾分区,中小系统不考虑这问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值