springboot+redis+mybatis体会布隆过滤器

1.建立数据库表和对应实体类

bash 复制代码
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uname` varchar(50) DEFAULT NULL,
  `usex` varchar(20) DEFAULT NULL,
  `uage` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1319 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
bash 复制代码
public class User {
    private String id;
    private String uname;
    private String usex;
    private String uage;

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUsex() {
        return usex;
    }

    public void setUsex(String usex) {
        this.usex = usex;
    }

    public String getUage() {
        return uage;
    }

    public void setUage(String uage) {
        this.uage = uage;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

2.编写Controller,新增用户和获取用户

bash 复制代码
@Controller
public class BloomController {
    @Autowired
    private BloomService bloomService;

    @RequestMapping(value = "/addUser")
    @ResponseBody
    public void addUser(){
        for(int i=0;i<100;i++){
            User user = new User();
            user.setUsex(i + "");
            user.setUname("user:" + i);
            user.setUage("26");
            bloomService.addUser(user);
        }

    }



    @RequestMapping(value = "/getUser")
    @ResponseBody
    public User getUser(HttpServletRequest request){
        String userId = request.getParameter("userId");
        User user = bloomService.getUser(userId);
        return  user;

    }

}

3.编写servie,实现具体的业务逻辑

bash 复制代码
public interface BloomService {
    void addUser(User user);

    User getUser(String userId);

    List<String> getUserIds();
}
bash 复制代码
@Service
public class BloomServiceImpl implements BloomService {

    public static final String redisKey = "USER:";

    @Resource
    private BloomDao bloomDao;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private BloomCheckUtil bloomCheckUtil;

    @Override
    public void addUser(User user) {
        int i = bloomDao.addUser(user);
        if(i>0){
            //mysql插入成功,将数据存入redis
            User currentUser = bloomDao.getUser(user.getId());
            redisTemplate.opsForValue().set(redisKey+user.getId(), JSONObject.toJSONString(currentUser));
        }


    }

    @Override
    public User getUser(String userId) {
        User user = null;
        //1.先从布隆过滤器中获取数据,若没有则直接返回
        if(!bloomCheckUtil.check(userId)){
            System.out.println("该用户id:" + userId +"不在合法用户内!!!!");
            return user;
        }
        //2.从redis中查找
        String rediskey = redisKey + userId;
        String jsonObj = Optional.ofNullable(redisTemplate.opsForValue().get(rediskey)).map(Object::toString).orElse(null);

         if(jsonObj == null){
             //3.redis中没有,查询数据库
             user = bloomDao.getUser(userId);
             if(user != null){
                 //4.redis无mysql有,把查询出的数据写入到redis缓存
                 redisTemplate.opsForValue().set(rediskey,JSONObject.toJSONString(user));
             }

             return user;
         }

        user =JSONObject.parseObject(jsonObj, User.class) ;
        return user;
    }

    @Override
    public List<String> getUserIds() {

        return bloomDao.getUserIds();
    }
}

4.编写dao和mapper,实现数据库操作

bash 复制代码
public interface BloomDao {
    int addUser(@Param("user") User user);

    User getUser(@Param("id")String id);

    List<String> getUserIds();
}
bash 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cn.study.redis.dao.BloomDao">

    <insert id="addUser"  parameterType="com.cn.study.redis.pojo.User" useGeneratedKeys="true" keyProperty="id">
        insert into user(uname,usex,uage) values (#{user.uname},#{user.usex},#{user.uage})
    </insert>

    <select id="getUser" resultType="com.cn.study.redis.pojo.User">
       select u.id ,u.uname ,u.usex ,u.uage  from user u where u.id = #{id}
    </select>

    <select id="getUserIds" resultType="String">
        select id from user
    </select>
</mapper>

5.编写布隆过滤器和工具类

bash 复制代码
@Component
public class BloomFilter {

    public static final String key = "LEGITIMATE_USER";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private BloomService bloomService;


    @PostConstruct
    public void init(){
        //初始化布隆过滤器
        //1.从数据库查出user表中的所有id,计算hash值
        List<String> userIdList = bloomService.getUserIds();

        for(int i=0;i<userIdList.size();i++){
            //对每个userId计算hash值并取绝对值
            int hashValue = Math.abs(("USER:" + userIdList.get(i)).hashCode());
            //使用hash值对2的32次方取余,得到下标
            long index = (long)(hashValue % Math.pow(2,32));

            System.out.println("id为:" + userIdList.get(i)+"的用户产生的hash值为:" + hashValue +",下标为:" + index);
            //将redis中对应下标的bitmap的值更新成1
            redisTemplate.opsForValue().setBit(key,index,true);
        }
    }
}
bash 复制代码
@Component
public class BloomCheckUtil {


    private static final String key = "LEGITIMATE_USER";

    @Autowired
    private RedisTemplate redisTemplate;

    public boolean check(String userId){
        boolean flag = false;

        int hashValue = Math.abs(("USER:" + userId).hashCode());

        long index = (long)(hashValue % Math.pow(2,32));

        flag = redisTemplate.opsForValue().getBit(key,index);

        return flag;

    }

}

7.验证

由于第一次启动项目的时候,BloomFilter 类中的init方法会在一开始执行,此时我还并没有调用addUser方法添加用户,数据库中没有任何用户信息,所以第一次启动项目的时候,布隆过滤器中不会有任何的数据。

我们启动项目后,手动调用下addUser方法,新增100条用户数据。

然后重启项目,将用户信息加载到布隆过滤器中。

我们调用getUser方法尝试获取用户信息,当我们传了一个数据库不存在的用户id时,当请求到布隆过滤器,布隆过滤器发现没有此数据,则直接返回,不会再往下查redis和mysql

相关推荐
Java水解5 小时前
Spring Boot 4 升级指南:告别RestTemplate,拥抱现代HTTP客户端
spring boot·后端
神云瑟瑟5 小时前
spring boot拦截器获取requestBody的最佳实践
spring boot·拦截器·requestbody
暮色妖娆丶5 小时前
Spring 源码分析 BeanFactoryPostProcessor
spring boot·spring·源码
南极企鹅6 小时前
springBoot项目有几个端口
java·spring boot·后端
清风拂山岗 明月照大江6 小时前
Redis笔记汇总
java·redis·缓存
忧郁的Mr.Li7 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
暮色妖娆丶8 小时前
SpringBoot 启动流程源码分析 ~ 它其实不复杂
spring boot·后端·spring
消失的旧时光-19438 小时前
第十四课:Redis 在后端到底扮演什么角色?——缓存模型全景图
java·redis·缓存
Coder_Boy_8 小时前
Deeplearning4j+ Spring Boot 电商用户复购预测案例中相关概念
java·人工智能·spring boot·后端·spring
爱学英语的程序员8 小时前
面试官:你了解过哪些数据库?
java·数据库·spring boot·sql·mysql·mybatis