缓存击穿 redis

发布时间 2023-11-15 18:03:30作者: wuyicode

缓存穿透

1、缓存穿透是指查询一个缓存中和数据库中都不存在的数据,导致每次查询这条数据都会透过缓存,直接查库,最后返回空。

解决缓存穿透的方法一般有两种,第一种是缓存空对象,第二种是使用布隆过滤器。

 

缓存击穿

2、缓存击穿是指当缓存中某个热点数据过期了,在该热点数据重新载入缓存之前,有大量的查询请求穿过缓存,直接查询数据库。

解决缓存击穿的方法也有两种,第一种是设置key永不过期;第二种是使用分布式锁。

 

试试双重检查 来避免 缓存击穿

 

import cn.hutool.json.JSONUtil;
import com.jin.pagehelper.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.math.BigInteger;
import java.util.Date;

@SuppressWarnings("all")
@Service
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @PostConstruct
    public void init() {
        if (redisTemplate.opsForHash().hasKey("employee", "1")) {
            redisTemplate.opsForHash().delete("employee", "1");
        }
    }

    public void setValueTest() {
        redisTemplate.opsForHash().put("employee", "1",
                JSONUtil.parse(
                        new Employee()
                                .setEmployeeId(BigInteger.valueOf(1))
                                .setFirstName("jin")
                                .setLastName("jin")
                                .setHireDate(new Date())
                )
        );
        System.out.println("ok");

    }

    public void getOps() throws InterruptedException {
        Object object = redisTemplate.opsForHash().get("employee", "1");
        if (object == null) {
            synchronized (this) {
                object = redisTemplate.opsForHash().get("employee", "1");
                if (object == null) {
                    System.out.println("redis没有,只能从数据库找");
                    setValueTest();
                } else {
                    System.out.println("并发情况下,从redis拿到了");
                }
            }

        } else {
            System.out.println("正常情况下,从redis拿到了");
        }
    }


}

 

自己模拟一个并发情况,做试验。

     ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 10; i++) {
            executorService.submit(() -> {
                try {
                    redisService.getOps();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }