BloomFilter如何快速检查用户名重复

 更新时间:2025年04月19日 09:34:20   作者:埃泽漫笔  
这篇文章主要介绍了BloomFilter如何快速检查用户名重复问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

背景

在我们的项目中,用户名是不能重复的,因为在数藏项目中,用户名的唯一性很重要,因为藏品要做溯源,要确保整个链路上的参与者的唯一性,虽然用户 id 也是我唯一的,但是页面上展示的时候不能用 id 呀。

有些网站,比如淘宝网,也是要求用户名唯一的。

所以为了实现这个用户在注册,改名的时候的用户名的唯一性,我们一般是先从数据库查询是否存在,不存在则让用户注册。

但是为了考虑到性能,我们会把用户名存储到缓存中,一般使用 redis 缓存。

那既然都用了缓存了,那还不如干脆直接就用布隆过滤器来存储,既可以做重复校验,又能节省空间。所以,我们在用户名重复检验这里就用到了布隆过滤器。

简介

布隆过滤器是一种数据结构,用于快速检索一个元素是否可能存在于一个集合(bit 数组)中。

它的基本原理是利用多个哈希函数,将一个元素映射成多个位,然后将这些位设置为 1。当查询一个元素时,如果这些位都被设置为 1,则认为元素可能存在于集合中,否则肯定不存在。

所以,布隆过滤器可以准确的判断一个元素是否一定不存在,但是因为哈希冲突的存在,所以他没办法判断一个元素一定存在。只能判断可能存在。

代码实现

所以,我们定义了两个方法,nickNameExist用于判断是否存在,addNickName用于向布隆过滤器中添加已注册的用户名。

public boolean nickNameExist(String nickName) {
    //如果布隆过滤器中存在,再进行数据库二次判断
    if (this.bloomFilter.contains(nickName)) {
        return userMapper.findByNickname(nickName) != null;
    }

    return false;
}

private boolean addNickName(String nickName) {
    return this.bloomFilter.add(nickName);
}

这里nickNameExist方法,先从布隆过滤器中查询,如果如果查到了,再去数据库中查了一下,为啥呢?

因为布隆过滤器有误判的,存在一定的误判率,他会把不存在的用户判断为存在,所以当检查结果是存在的时候,需要再次判断一次。

因为用户注册的时候,大多数情况下都是不重复的,所以我们可以快速的用布隆过滤器进行不存在的判断。

这里的bloomFilter是这样被初始化出来的:

private RBloomFilter<String> bloomFilter;

@Override
public void afterPropertiesSet() throws Exception {
    this.bloomFilter = redissonClient.getBloomFilter("nickName");
    if (!bloomFilter.isExists()) {
        this.bloomFilter.tryInit(10000000L, 0.01);
    }
}

我们设置了10000000的容量,误判率是0.01。

然后在修改用户名这里,用这样的方式进行调用的。

如果用户名修改了怎么办?

如果原来用户名是Aizer,被放到布隆过滤器了,但是后面我改成 Aizer666了,那么意味着 Aizer已经没有了,那么如何从布隆过滤器删除呢?

很遗憾,不支持!

那怎么办呢?

其实问题也不大,因为布隆过滤器本身就存在误判率,但我们检查布隆过滤器发现存在的时候,还是会去数据库再确认一遍的。

只要我们定期的重建一下布隆过滤器就行了。重建就是都删了,然后重新构建。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 深入学习Java单元测试(Junit+Mock+代码覆盖率)

    深入学习Java单元测试(Junit+Mock+代码覆盖率)

    在做单元测试时,代码覆盖率常常被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况,比如,代码覆盖率必须达到80%或 90%。下面我们就来详细学习下java单元测试吧
    2019-06-06
  • Java8中的default关键字详解

    Java8中的default关键字详解

    这篇文章主要介绍了Java8中的default关键字详解,在实现某个接口的时候,需要实现该接口所有的方法,这个时候default关键字就派上用场了。通过default关键字定义的方法,集成该接口的方法不需要去实现该方法,需要的朋友可以参考下
    2023-08-08
  • java String的intern方法

    java String的intern方法

    本文主要介绍java 中String 的intern方法,这里主要通过实例来说明不同版本的JDK,intern方法的对比,有需要的小伙伴可以参考下
    2016-07-07
  • IntelliJ Idea2017如何修改缓存文件的路径

    IntelliJ Idea2017如何修改缓存文件的路径

    这篇文章主要介绍了IntelliJ Idea2017如何修改缓存文件的路径,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Java 如何获取某年的第一天和最后一天

    Java 如何获取某年的第一天和最后一天

    在统计的数据是时候,要统计某年的数据,开始时间是某年的第一天,结束时间是某年的最后一天,该如何获取某年的第一天和最后一天,今天通过本文介绍下Java获取某年的第一天和最后一天,需要的朋友可以参考下
    2023-07-07
  • Springboot通过配置WebMvcConfig处理Cors非同源访问跨域问题

    Springboot通过配置WebMvcConfig处理Cors非同源访问跨域问题

    这篇文章主要介绍了Springboot通过配置WebMvcConfig处理Cors非同源访问跨域问题,关于Cors跨域的问题,前端有代理和jsonp的常用方式解决这种非同源的访问拒绝策略
    2023-04-04
  • Java 延时队列及简单使用方式详解

    Java 延时队列及简单使用方式详解

    这篇文章主要介绍了Java延时队列简单使用方式,通过本文学习知道延时队列是什么可以用来干什么,本文通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • Springboot集成Mybatis-Flex的示例详解

    Springboot集成Mybatis-Flex的示例详解

    Mybatis-Flex 是一个优雅的 Mybatis 增强框架,它非常轻量、同时拥有极高的性能与灵活性,本文主要介绍了Springboot集成Mybatis-Flex的示例详解,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Java将byte[]转图片存储到本地的案例

    Java将byte[]转图片存储到本地的案例

    这篇文章主要介绍了Java将byte[]转图片存储到本地的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • 详解如何热更新线上的Java服务器代码

    详解如何热更新线上的Java服务器代码

    这篇文章主要介绍了详解如何热更新线上的Java服务器代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04

最新评论