场景:
当大量请求过来查询redis,redis无该数据,数据库也无该数据,所有请求指向数据库,这时会造成数据库崩溃,该现象称为redis缓存穿透
两种解决方案:
一、当redis无该数据去查数据库,数据库无该数据时,在redis中存入空
@GetMapping("info/{id}")
public R getInfo(@PathVariable("id") String id){
Object order = redisUtil.get(id);
if (order == null){
System.out.println("查询数据库");
order = orderService.getById(id);
if (order != null){
redisUtil.set(id,order);
}
// 数据库也无此数据,在redis中存入空数据
redisUtil.set(id,"无此数据");
}
return R.ok().data("order",order);
}
结论:
- redis中会存入大量空数据,占用内存;
- 只是针对某个key,当有大量不同key请求依然存在问题
二、使用布隆过滤器
1.maven依赖
<!-- guava引入布隆过滤器 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
2.创建业务类BloomFilterImpl
package com.example.order.service.impl;
import com.example.order.mapper.UserOrderMapper;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
/**
* @author xiaozikang
* @date 2020/10/18 15:47
* @Email:xiaozikangwy@163.com
*/
@Component
public class BloomFilterImpl {
// 预存的数据个数 100w
private static int expectedInsertions = 1000000;
//可接受的错误率
private static double fpp = 0.001;
// 创建布隆过滤器的对象
private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(),expectedInsertions,fpp);
@Resource
private UserOrderMapper orderMapper;
/**
* BloomFilterImpl对象被创建后,立即初始化的方法
*/
@PostConstruct
public void initData(){
// 查询数据库中所有的id
List<Integer> ids = orderMapper.selectAllIds();
// 初始化到布隆过滤器中
for (Integer id : ids) {
bloomFilter.put(id);
}
}
/**
* 判断布隆过滤器中是否存在该id
* @param id
* @return
*/
public boolean mightContain(Integer id){
return bloomFilter.mightContain(id);
}
}
3.使用布隆过滤器判断
@GetMapping("info/{id}")
public R getInfo2(@PathVariable("id") Integer id){
Object order = redisUtil.get(String.valueOf(id));
if (order == null){
// 判断布隆过滤器是否已经存在
boolean b = bloomFilter.mightContain(id);
if (!b){
return R.error().message("查询无果");
}
System.out.println("查询数据库");
order = orderService.getById(id);
if (order != null){
redisUtil.set(String.valueOf(id),order);
}
return R.error().message("查询无果");
}
return R.ok().data("order",order);
}
结论:
- 为了保证布隆过滤器与数据库一致,数据库进行增删也得同步redis和布隆过滤器