缓存穿透是:就是查询一个不存在缓存的key 每次都去查询了数据库 导致数据库压力增大
缓存击穿是:一个热点key,查询缓存的时候,缓存没有,大量的请求打进了数据库
布隆过滤器:如果为true,不一定存在,如果为false,一定不存在;
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.6.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.11</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在项目初始化的时候,把数据放入布隆过滤器中,和redis中
package com.example.demo.init;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
/**
* 项目启动的时候,进行初始化
*/
@Component
public class MyInitializing implements InitializingBean {
@Autowired
private RedissonClient redissonClient;
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化--------------------------------------------------");
//创建布隆过滤器 过滤器的名称
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("guo-lv-qi-name");
//第一个参数表示大小 预期插入数量,第二个参数表示错误概率,错误概率不能大于 1,错误概率不能为负
bloomFilter.tryInit(10000,0.03);
//模拟数据库查询出来的数据
String id="1";
String value="你好";
//把id放入布隆过滤器
bloomFilter.add(id);
//把数据放入缓存
redisTemplate.opsForValue().set(id,value);
}
}
package com.example.demo.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
// 配置对象
Config config = new Config();
//单节点 地址 redis://ip:6379
config.useSingleServer().setAddress("redis://192.168.184.142:6379");
//创建配置
return Redisson.create(config);
}
}
配置文件
# 应用名称
spring.application.name=demo3
# 应用服务 WEB 访问端口
server.port=9003
spring.redis.host=192.168.184.142
spring.redis.port=6379
package com.example.demo.controller;
import com.example.demo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
private TestService testService;
@GetMapping("/test")
public String test(String id){
return testService.test(id);
}
}
package com.example.demo.service;
public interface TestService {
public String test(String id);
}
package com.example.demo.service.impl;
import com.example.demo.service.TestService;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
@Service
public class TestServiceImpl implements TestService {
@Autowired
private RedissonClient redissonClient;
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public String test(String id) {
//先通过布隆过滤器查看是否存在这个id 过滤器的名称
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("guo-lv-qi-name");
//第一个参数表示大小 预期插入数量,第二个参数表示错误概率,错误概率不能大于 1,错误概率不能为负
bloomFilter.tryInit(10000,0.03);
if(!bloomFilter.contains(id)){
return "查询的数据不存在";
}
//如果存在 在查询缓存
String s = redisTemplate.opsForValue().get(id);
if(null!=s){
//如果缓存不为空 直接返回缓存的数据
return s;
}
//如果缓存不存在 那么查询数据库
//我这里模拟下数据库 造2条假数据 id=1 存在 ,id=其他不存在
if("1".equals(id)){
//存在数据库 把查询出来的数据放入缓存
redisTemplate.opsForValue().set(id,"你好");
//然后返回给前端
return "你好";
}else {
//如果数据库不存在 直接返回其他数据给前端
return "数据库不存在";
}
}
}
我们来看下效果,访问一个不存在的数据
我们在来查询一个存在的数据
在项目启动的时候,我们的redis就有了数据
最终可以看到,我们通过布隆过滤器,先去判断存不存在,
如果不存在,直接返回;
如果存在,在去查询缓存;
如果缓存存在,直接返回缓存的数据;
如果缓存不存在,在查询数据库,并把数据库的数据,放入缓存;
如果数据库的数据不存在,返回空;