业务设计——分库分表下多种登录方式实现【用户名、邮箱、手机号】

news2024/11/18 5:29:21

业务需求:

实现多种方式的登录流程,要求对用户数据采用分库分表来实现水平扩展

难点分析

难点一

        用户登录方式需智能匹配,确保根据其输入的数据类型来确定登录方式,查询数据库指定字段,避免无用查询导致资源浪费

难点二

        分库分表下,数据散落到多个表中,查询复杂度高,需要在多个登录方式中锁定用户详细数据表的分片键才能定位最终的用户数据结果返回


解决思路

难点一思路

下面是三个常用获取用户选择的登录方式的方法

  • 用户自主选择:在登录页面上提供多个登录选项,例如用户名、邮箱、手机号等,用户可以根据需要选择相应的登录方式。你可以使用单选按钮、下拉列表或者切换按钮等方式来呈现选项。

  • 输入识别:在用户输入登录凭证时,通过验证凭证的格式来判断用户选择的登录方式。这里可以采用正则表达式匹配的方式,例如,如果输入符合手机号的格式,则可以自动识别为手机号登录;如果输入符合邮箱格式,则可以自动识别为邮箱登录;否则,可以默认为用户名登录。

  • 预设默认登录方式:如果用户在注册或设置账号时已经选择了默认的登录方式,可以在登录页面上预设默认的登录方式,让用户直接输入对应的凭证进行登录。


难点二思路

现在的问题是无论我们采用哪种登录方式,最终我们要返回去的都是一样的用户详情数据,而对于用户详情数据,我们也是采用分库分表的方式来进行水平扩展,那么我们想要高效得锁定该用户数据在哪个子表位置上(避免读扩散现象),就要求我们获取到该用户详情表的分片键才行,而多种登录方式就会让分片键数据无法直接被获取(用户一栏明确标出可以使用用户名、邮箱或手机号中的任意一个搭配密码进行登录。需要强调的是,在分库分表中,我们是通过用户名进行分片的。因此,如果在查询用户信息时不带用户名,将会触发读扩散问题。)

为此,引入“路由表”来解决

什么是路由表?

        在分库分表中,路由表(Routing Table)是一个用于映射用户数据在分片库和分片表中位置的特殊表。它记录了用户按照特定分片键(例如用户名、邮箱、手机号等)拆分后在哪个分片库的哪张分片表中。

路由表的存在使得系统可以根据不同的登录方式(用户名、邮箱、手机号)来准确地定位到用户数据所在的分片位置,从而能够在查询时快速找到对应的数据。

路由表优点

        通过路由表的映射,系统可以快速定位用户数据所在的分片位置,从而实现按照不同的登录方式进行查询。这样,无论用户是通过用户名、邮箱还是手机号登录,系统都能准确地找到对应的数据所在位置,从而提高了查询的效率和准确性。

        拿手机号登录方式来说,我们通过手机号定位到路由表中的某一条用户数据,拿到对应的用户名,再根据用户名去查询真实的用户数据。这样就很好避免了读扩散问题。

路由表缺点

当然,路由表也不是万能的,同样存在着一些不好的点,比如:

  • 查询性能:在进行用户登录或其他需要根据分片键查找数据的操作时,需要先访问路由表,根据分片键的取值范围定位到对应的分片位置,然后再去实际的分片库和分片表中查询数据。这样的查询过程会引入额外的查询开销,可能影响系统的查询性能。
  • 维护成本:随着系统数据量的增加和业务发展,路由表的大小和复杂度可能会不断增加,维护路由表将会变得越来越复杂。对于大规模分库分表系统,路由表的维护成本可能会很高。

总结一下该类业务的简要流程步骤

简要流程步骤

假设用户详情表的分表键为用户名,支持用户名 / 邮箱 / 电话 + 密码的登录场景

  1. 后端设置匹配规则确定用户的登陆方式,根据登陆方式来调用对应分支逻辑执行登录流程
  2. 用户名登录
    1. 直接根据用户名数据 + 密码进行查表查询,返回查表结果
  3. 非用户名登录
    1. 首先通过查询路由表,根据邮箱 / 电话号匹配到用户名结果(这一步可以设置一个匹配缓存数据表,减少数据库IO,但是要求注意修改用户名后的缓存一致性保证)
    2. 结果为空直接失败,结果不为空执行2.1.一样的逻辑

数据库表设计例子

业务代码例子 

@Override
    public UserLoginRespDTO login(UserLoginReqDTO requestParam) {
        String usernameOrMailOrPhone = requestParam.getUsernameOrMailOrPhone();
        boolean mailFlag = false;
        // 时间复杂度最佳 O(1)。indexOf or contains 时间复杂度为 O(n)
        for (char c : usernameOrMailOrPhone.toCharArray()) {
            if (c == '@') {
                mailFlag = true;
                break;
            }
        }
        String username;
        if (mailFlag) {
            LambdaQueryWrapper<UserMailDO> queryWrapper = Wrappers.lambdaQuery(UserMailDO.class)
                    .eq(UserMailDO::getMail, usernameOrMailOrPhone);
            username = Optional.ofNullable(userMailMapper.selectOne(queryWrapper))
                    .map(UserMailDO::getUsername)
                    .orElseThrow(() -> new ClientException("用户名/手机号/邮箱不存在"));
        } else {
            LambdaQueryWrapper<UserPhoneDO> queryWrapper = Wrappers.lambdaQuery(UserPhoneDO.class)
                    .eq(UserPhoneDO::getPhone, usernameOrMailOrPhone);
            username = Optional.ofNullable(userPhoneMapper.selectOne(queryWrapper))
                    .map(UserPhoneDO::getUsername)
                    .orElse(null);
        }
        username = Optional.ofNullable(username).orElse(requestParam.getUsernameOrMailOrPhone());
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getUsername, username)
                .eq(UserDO::getPassword, requestParam.getPassword())
                .select(UserDO::getId, UserDO::getUsername, UserDO::getRealName);
        UserDO userDO = userMapper.selectOne(queryWrapper);
        if (userDO != null) {
            UserInfoDTO userInfo = UserInfoDTO.builder()
                    .userId(String.valueOf(userDO.getId()))
                    .username(userDO.getUsername())
                    .realName(userDO.getRealName())
                    .build();
            String accessToken = JWTUtil.generateAccessToken(userInfo);
            UserLoginRespDTO actual = new UserLoginRespDTO(userInfo.getUserId(), requestParam.getUsernameOrMailOrPhone(), userDO.getRealName(), accessToken);
            distributedCache.put(accessToken, JSON.toJSONString(actual), 30, TimeUnit.MINUTES);
            return actual;
        }
        throw new ServiceException("账号不存在或密码错误");
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1139800.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CVPR2023 即插即用 SCConv (附代码)

论文地址&#xff1a;SSCONV 代码地址&#xff1a;https://github.com/cheng-haha/ScConv 1.是什么&#xff1f; SCConv是一种高效的卷积模块&#xff0c;用于压缩卷积神经网络中的冗余特征&#xff0c;以减少计算负荷并提高模型性能。它由空间重构单元(SRU)和信道重构单元(…

如何保障单病种上报的填报效率、质量监控及数据安全

在国家平台对单病种病例进行手工直报&#xff0c;是大多数医院最初获知《关于进一步加强单病种质量管理与控制工作的通知》后的首选方式。随着医院对上报流程与内容的逐步熟练&#xff0c;质控管理的需求开始凸显并占据主要地位&#xff0c;同时为了能更好地适应国家平台的频繁…

基于STM32设计的万能红外遥控器(学习型)

一、项目设计 基于STM32设计的万能红外遥控器(学习型) 随着智能家居和物联网技术的发展,红外遥控器作为传统的智能设备控制方式逐渐被淘汰,但在某些场景下,红外遥控器仍然是一种快速、简单的操作方式,当前介绍了一种基于STM32微控制器设计的红外遥控器,支持接收解码功能和…

谁在成为产业供应链的“新发动机”?

京东供应链金融路径不仅是金融的助力和加持&#xff0c;也更是京东供应链金融科技在产业侧的更有价值表达&#xff0c;推动当下产业数字互联从点到线&#xff0c;再到网的更大程度协同。 作者|皮爷 出品|产业家 2022年&#xff0c;一款名为“海油e融”的融资产品出现在市面…

CSS色域、色彩空间、CSS Color 4新标准 | 京东云技术团队

引言 近期&#xff0c;三大主流浏览器引擎均发布最新版本&#xff0c;支持W3C的CSS Color 4标准&#xff0c;包含新的取色方法color()和相应语法&#xff0c;可展示更多的色域及色彩空间&#xff0c;这意味着web端能展示更丰富更高清的色彩。虽然目前只有最新版本的现代浏览器…

非对称加密算法RSA的深度解析,在CTF中RSA题目

一、背景 现代密码体系中&#xff0c;主要分为两类&#xff0c;对称加密和非对称加密两大类。在安全性方面上&#xff0c;非对称加密以安全可靠&#xff0c;在互联网中特别广泛的使用&#xff0c;就如我们平时接触到的https的TLS等一些证书的实现&#xff0c;也深得非对称加密…

showdoc 文件上传 (cnvd-2020-26585)

showdoc 文件上传 &#xff08;cnvd-2020-26585&#xff09; 描述 ShowDoc是一个非常适合IT团队的在线API文档、技术文档工具。通过showdoc&#xff0c;你可以方便地使用markdown语法来书写出美观的API文档、数据字典文档、技术文档、在线excel文档等等。 api_page存在任意文…

漏洞复现-showdoc文件上传_v2.8.3_(CNVD-2020-26585)

showdoc文件上传_v2.8.3_CNVD-2020-26585 漏洞信息 showdoc 2.8.3 以下版本中存在安全漏洞CNVD-2020-26585文件上传漏洞 描述 ShowDoc是一个非常适合IT团队的在线API文档、技术文档工具。通过showdoc&#xff0c;你可以方便地使用markdown语法来书写出美观的API文档、数据字…

做国外问卷调查的工作靠谱吗?

哈喽大家好&#xff0c;我是橙河网络&#xff0c;最近网上都在传做问卷能赚美金的项目&#xff0c;也就是“海外问卷调查”&#xff0c;我在这跟大家简单唠唠它是个啥&#xff0c;做国外问卷调查的工作靠谱吗&#xff1f; 海外问卷调查&#xff0c;顾名思义&#xff0c;就是我…

开始学习Go编程

探索Go编程中的语法、数据类型和控制流 Go&#xff0c;又称为Golang&#xff0c;因其简单性、性能和效率而广受欢迎。在本文中&#xff0c;我们将深入研究构成Go编程语言基础的基本概念。从理解其语法和数据类型到掌握控制流和函数&#xff0c;我们将为您提供启动Go编程之旅所…

芋道前后端分离项目跳过登录

后端接口 1. nacos配置 根据以上两图可以发现芋道的跳过登录配置在nacos或者yml可以配置成如下样式 将所有需要跳过登录的方法写在permit-all_urls下级即可 2. PermitAll注解&#xff1a;不管登入,不登入 都能访问 注&#xff1a;如果一个页面有多个接口那么所有接口均需要写…

【算法-数组1】二分查找 和 移除元素

今天&#xff0c;带来XXX的讲解。文中不足错漏之处望请斧正&#xff01; 理论基础 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#…

AMEYA360:炬玄智能车规级RTC芯片JXR191T为车载BMS提供16年稳态输出

北京炬玄智能科技有限公司聚焦于集成电路时钟芯片研发及生产&#xff0c;以高精度、高稳定性、集成化芯片和系统设计为主要方向&#xff0c;以实时时钟芯片(RTC)及模组为切入点&#xff0c;逐步将产品拓展到以TCXO、OCXO为代表的高端晶振芯片领域&#xff0c;最终打通整个时钟产…

探讨Java多线程调度:如何实现两线程并行,一线程等待?

亲爱的小伙伴们&#xff0c;大家好&#xff01;我是小米&#xff0c;很高兴再次和大家分享一些关于Java编程的有趣技巧和知识。今天&#xff0c;我们将探讨一个有趣且常见的面试问题&#xff1a;如何让两个线程同时执行&#xff0c;而第三个线程必须等待前两个线程结束后才能开…

trucksim常见问题

一、Error: Unable to load .vs data from “D:\Users\Public\Documents\TruckSim2019.0 Data\Results\Run_e24aa2… LastRun.vs”.Reason for failure: Invalid character OxFFFFFFB2 in string"" on line 4.Would you like to continue receiving alerts of this t…

RPA厂商大比拼,哪家才更适合您?

引言&#xff1a;随着数字化时代的到来&#xff0c;自动化已成为推动企业数字化发展的关键举措之一&#xff0c;RPA作为自动化中的重要技术之一&#xff0c;可为企业提供了实现业务流程自动化的强大工具。然而&#xff0c;如何选择适合自己的RPA厂商也是各大企业现在面临的难题…

调试-Debug

0.1 Debug环境介绍 Microsoft Visual Studio 2022中&#xff1a; Debug版本的可执行程序称为调试版本&#xff0c;包含调试信息&#xff0c;不作任何优化&#xff0c;便于程序员进行调试。 Release版本的可执行程序称为发布版本&#xff0c;进行了各种优化&#xff0c;不可调…

小红书内容运营包含哪些,内容种草攻略

在这个社交属性&#xff0c;强势泛滥的年代&#xff0c;兼具了社交和电商两大功能的小红书&#xff0c;已经成为品牌方的兵家必争之地。今天来为大家分享下小红书内容运营包含哪些&#xff0c;内容种草攻略&#xff01; 1、确定账号定位 这是做好小红书内容运营的第一步。一个有…

扫地机器人,不相信视觉导航

不可置否&#xff0c;激光雷达已经成为扫地机器人的“耶路撒冷”。 导航技术的从无到有 回顾扫地机器人的兴衰&#xff0c;本质是导航技术的从无到有、从弱到强、从少到多&#xff0c;而在这个过程中&#xff0c;激光雷达无疑发挥了无可替代的作用。2010年&#xff0c;第一台…

实时嵌入式系统环境中敏捷的基础

不同的人使用敏捷一词的含义不同。在计算中&#xff0c;该术语最初用于描述执行项目开发的轻量级方法&#xff0c;而最初的术语极限编程&#xff08;XP&#xff09;未能激发受托管理开发项目的众多管理人员。 基本上&#xff0c;敏捷软件开发指的是一组松散集成的原则和实践&a…