基于Redis实现全局唯一Id

news2024/12/24 2:52:42

 微信公众号访问地址:基于Redis实现全局唯一Id

推荐文章:

    1、使用原生Redis命令实现分布式锁

​    2、为什么引入Redisson分布式锁?

    3、SpringBoot整合多数据源,并支持动态新增与切换(详细教程)

    4、SpringBoot统一标准响应格式及异常处理

   5、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据

一、简介

使用数据库自增ID就存在一些问题:

    1、受单表自增数量的限制;

      原因:mysql单表的容量不宜超过500W条,数据量过大之后,就需要进行拆库拆表,但拆分表之后,它们从逻辑上讲仍然是同一张表,所以他们的id是不能一样的(不同表,若使用自增ID,是可能一样的),所以随着我们的业务数据越来越大,我们需要保证id的唯一性。

    2、id的规律性太明显。

      原因:自增id具有太明显的规则,用户或者说商业对手很容易猜测出来一些敏感信息,例如:在一天时间内,我们卖出了多少单,这明显不合适。

二、全局唯一ID生成策略

      一般要满足下列特性:

      为了增加ID的安全性,可以不直接使用Redis自增的数值,而是拼接一些其它信息:

组成说明:

    1、符号位:1bit,永远为0;

    2、时间戳(31 Bit):31bit,以秒为单位,可以使用69年;

    3、序列号:32bit,秒内的计数器,支持每秒产生2^32个不同ID。

三、基于Redis实现全局唯一Id案例

    原理:基于Redis 的INCR 命令生成分布式全局唯一id。INCR 命令主要有以下2个特征:

      1、具备了“INCR AND GET”的原子操作,即:增加并返回结果的原子操作。这个原子性很方便我们实现获取ID。

      2、Redis是单进程单线程架构,INCR命令不会出现id重复。

3.1、构建RedisIdUtils类

/**
 * 功能描述:使用redis生成全局唯一ID
 * @Author: yyalin
 * @CreateDate: 2023/8/13 11:35
 */
@Component
public class RedisIdUtils {
    //预生成开始时间戳
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    //序列号的位数
    private static final int COUNT_BITS = 32;
    //redis提供的字符串
    private StringRedisTemplate stringRedisTemplate;
    //有参构造函数
    public RedisIdUtils(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }
    /**
     * 功能描述:根据keyPrefix前缀生成对应业务的全局唯一ID
     * @MethodName: nextId
     * @MethodParam: [keyPrefix:使用前缀来区分不同的业务]
     * @Return: long
     * @Author: yyalin
     * @CreateDate: 2023/8/13 12:20
     */
    public long nextId(String keyPrefix) {
        // 1.生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond - BEGIN_TIMESTAMP;
        // 2.生成序列号
        // 2.1.获取当前日期,精确到天
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 2.2.自增长 icr:order:2023:08:13
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
        // 3.拼接并返回  timestamp << COUNT_BITS :向左移动32位
        //原本时间戳在低位上,通过向左移动32位,变位到高位存储,低32位都是0,然后与自增序列按位操作
        //形成低32位为序列号。
        return timestamp << COUNT_BITS | count;
    }
}

3.2、构建多线程测试类

** * @Description: TODO:测试RedisIdUtils * @Author: yyalin * @CreateDate: 2023/8/13 12:27 * @Version: V1.0 */@Service@Slf4jpublic class TestRedisIdUtils {    @Autowired    private RedisIdUtils redisIdUtils;    //使用自定义的线程池    private ExecutorService executorService = Executors.newFixedThreadPool(500);    /**     * 功能描述:使用多线程测试生成40000条数据耗时     * @MethodName: testIdWorker     * @MethodParam: [nums]     * @Return: void     * @Author: yyalin     * @CreateDate: 2023/8/13 12:36     */    public void testIdWorker(int nums) throws InterruptedException {        //同步协调在多线程的等待于唤醒问题 分线程全部走完之后,主线程再走        CountDownLatch latch = new CountDownLatch(nums);        Runnable task = () -> {            for (int i = 0; i < 100; i++) {                long id = redisIdUtils.nextId("order");                System.out.println("id = " + id);            }            latch.countDown();        };        long begin = System.currentTimeMillis();        for (int i = 0; i < nums; i++) {            executorService.submit(task);        }        //阻塞方法 让main线程阻塞        latch.await();        long end = System.currentTimeMillis();        log.info("生成"+nums*100+"条id共计耗时(毫秒) = " + (end - begin));    }}

3.3、测试结果

序列
 
线程数条数耗时(秒)
1500300000.781
2500400000.993
3500500001.164

      总结:从测试结果不难看出,基于redis实现全局唯一ID,性能还是非常高的,并且耗时非常短的。

更多优秀文章,请关注个人微信公众号或搜索“程序猿小杨”查阅。

参考文章:

https://blog.csdn.net/weixin_43811057/article/details/130798254

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

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

相关文章

【计算机网络】Udp详解

前言 上几文章我们讲解了应用层协议Http和Https&#xff0c;要知道应用层协议有很多&#xff0c;这些都是程序员自己定制的&#xff0c;而真正要传输的时候&#xff0c;是要在操作系统的传输层进行的&#xff0c;今天我们就来学习一下传输层协议Udp的 标识一个通信 要进行跨…

黑马项目一阶段面试 自我介绍篇

面试官你好&#xff0c;我叫xxx&#xff0c;是来自xxxx的本科毕业生。我通过招聘网站/内推/线下招聘了解到的贵司&#xff0c;我具有扎实的Java后端的基础功底&#xff0c;基本掌握JavaSE、JavaEE流行技术的使用&#xff0c;并且我比较好学&#xff0c;心态也很乐观积极&#x…

docker nginx ssl设置

使用docker运行nginx&#xff0c;配置代理&#xff0c;和ssl设置&#xff0c;进行https访问 一 准备 本次在centos环境中 1.已安装docker&#xff0c;docker-compose 2.运行了一个后端服务容器&#xff0c;提供基本的接口访问【可选】 3.一个域名&#xff08;已经解析到服…

Linux命令200例:date用于显示和设置系统的日期和时间

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

MongoDB 更新文档(更新数组对象中的元素)

之前我们介绍了如何更新文档&#xff0c;并简单的介绍了更新文档时可以使用选项进行指定当更新内容不存在时&#xff0c;可以进行新增文档。具体可以参考&#xff1a; MongoDB 更新文档(更新一条文档)https://blog.csdn.net/m1729339749/article/details/129983304 最近遇到了…

Android实现超出固定行数折叠文字“查看全文“、“收起全文“

先上效果图 分析问题 网上有很多关于这个的代码&#xff0c;实现都过于复杂了&#xff0c;github上甚至还看到一篇文章600多行代码&#xff0c;结果一跑起来全是bug。还是自己写吧&#xff01;&#xff01;&#xff01; 如果我们需要换行的"查看全文"、"收起全…

用汇编指令求两个数的最大公约数 求for循环实现1~100

1.用汇编指令求两个数的最大公约数 2.用汇编指令求for循环实现1~100

【校招VIP】测试计划之黑盒测试白盒测试

考点介绍&#xff1a; 黑盒测试&白盒测试是大厂和三四线公司校招的必考点。黑盒是以结果说话&#xff0c;白盒往往需要理解实现逻辑。现在商业项目的接口测试往往以白盒为主&#xff0c;也就是需要测试同学自己观察和修改数据库的值进行用例的测试。 但是无论采用哪种测试方…

尚硅谷大数据项目《在线教育之离线数仓》笔记001

视频地址&#xff1a;尚硅谷大数据项目《在线教育之离线数仓》_哔哩哔哩_bilibili 目录 P003 P004【数仓概念讲的颇为详细】 P018 P019 P020 P021 P022 P023 P024 P003 时间切片&#xff1a;时间回溯&#xff0c;找回以前的数据。 P004【数仓概念讲的颇为详细】 核心架…

华为OD机试 - 数据最节约的备份方法 - 二分查找(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、解题思路解题思路如下&#xff1a;解题思路分析&#xff1a; 五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 一、题目描述 有若干个文件&#xff0c;使用刻录光盘…

14k字综述视觉大模型

目录 0.导读1.背景介绍1.1基础架构1.2目标函数1.2.1对比式学习1.2.2生成式学习1.3预训练1.3.1预训练数据集1.3.2微调1.3.3提示工程2.基于文本提示的基础模型2.1基于对比学习的方法2.1.1基于通用模型的对比方法2.1.2基于视觉定位基础模型的方法2.2基于生成式的方法2.3基于对比学…

考公-判断推理-逻辑判断

且和或 只能有一个人是我老婆&#xff0c;要么小红&#xff0c;要么小丽&#xff0c;不可能都是我老婆&#xff0c;虽然有些人心里是这么想的 虽然&#xff0c;但是&#xff0c;且 虽然我很丑&#xff0c;但是我很温柔 或的翻译&#xff0c;否一推一 例题 例题 德摩根 例题…

数据可视化工具的三大类报表制作流程分享

电脑&#xff08;pc&#xff09;、移动、大屏三大类型的BI数据可视化报表制作步骤基本相同&#xff0c;差别就在于尺寸调整和具体的报表布局。这对于采用点击、拖拉拽方式来制作报表的奥威BI数据可视化工具来说就显得特别简单。接下来&#xff0c;我们就一起看看不这三大类型的…

全网最全360无死角编写软件测试用例模板【建议收藏】

总体编写策略&#xff1a; 对于测试用例编写来说&#xff0c;常用的四种方法基本就够用了&#xff0c;等价类、边界值、正交实验法、错误推断法&#xff0c;辅以场景测试法、需求/设计转换法、探索式测试思想&#xff0c;可以应付绝大多数产品的测试。个别的产品还需要在某一点…

nestjs 基础、使用 passport 来进行鉴权

回顾一些定义 NestJS 部分 Module 模块结构 模块是一个图状引用关系。 模块的实例化有三种模式。默认情况是 singletones 模式&#xff0c;也就是模块可能被引用&#xff0c;但不同的引用处拿的是同一个共享实例&#xff0c;也就是说一个进程有一个唯一的实例被共享。 模块&a…

动态设备状态监测:智能化生产的关键利器

动态设备状态监测正引领着工业生产的智能化转型。本文将深入探讨动态设备状态监测的意义、PreMaint在其中的角色&#xff0c;以及如何实现智能化生产&#xff0c;提高生产效率和可靠性。 1. 动态设备状态监测的重要性 随着制造业的发展&#xff0c;设备的状态监测变得至关重要…

小程序制作教程:从零开始搭建企业小程序

在如今的数字化时代&#xff0c;企业介绍小程序成为了企业展示与推广的重要工具。通过企业介绍小程序&#xff0c;企业可以向用户展示自己的品牌形象、产品服务以及企业文化等内容&#xff0c;进而提高用户对企业的认知度和信任度。本文将介绍如何从零开始搭建一个企业介绍小程…

基于深度信念网络的西储大学轴承故障分类识别,基于EMD+DBN的西储大学轴承故障识别,LCD+DBN,LMD+DBN

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) (EMD,LCD,LMD)+DBN的深度信念网络的西储大学轴承故障分类识别 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类…

都说go协程性能好,这次我们来试试java协程

java 协程原理 在Java中&#xff0c;协程&#xff08;Coroutine&#xff09;是一种轻量级的线程解决方案&#xff0c;它可以在代码中实现类似于多线程的并发操作&#xff0c;但不涉及线程的创建和切换开销。 在传统的Java多线程编程模型中&#xff0c;线程的切换开销较大&…

18.本地存储

18.1本地存储分类- localStorage 1.作用: 可以将数据永久存储在本地(用户的电脑)&#xff0c;除非手动删除&#xff0c;否则关闭页面也会存在 2.特性: ●可以多窗口(页面)共享(同一浏览器可以共享) ●以键值对的形式存储使用&#xff0c;键值除了数字型都要加引号 3.语法 存…