SpringBoot生成唯一ID的方式
1.为什么要生成唯一ID?
数据唯一性:每个记录都需要有一个独一无二的标识符来确保数据的唯一性。这可以避免重复的数据行,并有助于准确地查询、更新或删除特定的记录。
数据完整性:通过使用唯一ID,可以保证数据库中的数据完整性。例如,在关系数据库中,外键通常引用主表的唯一ID,以建立和维护表之间的关联。
高效查询:唯一ID通常是索引的一部分,这意味着使用它们进行查询可以非常快速和高效。这对于提高应用程序性能特别重要,尤其是在处理大量数据时。
简化逻辑处理:拥有一个唯一的标识符可以简化很多业务逻辑的处理。例如,当需要引用或共享特定数据项时,唯一ID提供了一个简单而直接的方法。
分布式系统支持:在分布式系统或微服务架构中,唯一ID(特别是全局唯一ID)是必不可少的。它们允许不同的服务能够独立生成不冲突的ID,从而简化了跨服务的数据整合和通信问题。
易于扩展和维护:随着系统的发展和需求的变化,唯一ID使得添加新功能或者修改现有功能变得更加容易。例如,重构数据库结构时,唯一ID可以帮助更平滑地迁移数据。
2.生成唯一ID的基本要求
唯一性:这是最基本的要求,即生成的ID在整个系统中必须是独一无二的。特别是在分布式系统中,需要确保不同节点生成的ID也不会发生冲突。
全局唯一性(如果适用):在某些场景下,如分布式系统或微服务架构中,可能需要ID不仅在同一数据库或系统内唯一,而且在所有相关的系统和数据库中也保持唯一。
不可预测性:为了安全考虑,尤其是在涉及用户敏感信息或重要业务逻辑时,ID应该是难以预测的。这可以防止恶意猜测或其他安全问题。
顺序性(如果需要):有些应用可能需要ID有一定的顺序性,例如按时间顺序排列,以便于排序、分页等操作。但需要注意的是,严格的顺序性可能会对系统的扩展性和性能造成影响。
高效性:生成ID的过程应该尽可能快速且消耗资源少,以避免成为系统性能瓶颈。
长度适中:ID的长度应该适中,既能保证足够的空间来确保唯一性,又不至于过长导致存储和传输效率降低。
兼容性:生成的ID应与现有的系统和协议兼容,不会因为格式或编码问题而引起错误。
可扩展性:随着系统的发展和规模的增长,生成ID的方法应能方便地进行扩展,以适应更高的需求。
3.常见生成方法
- UUID(通用唯一识别码)
基于时间的UUID(Version 1):结合时间戳和MAC地址生成。
基于随机数的UUID(Version 4):使用随机数生成。
基于命名空间的UUID(Version 3 和 5):基于命名空间和名称的哈希值生成。
优点:
全局唯一性:UUID的设计保证了在全球范围内的唯一性,适用于分布式系统。
无需中央协调:无需依赖数据库或其他中央服务生成ID,减少了系统复杂性。
生成速度快:基于随机数的UUID生成速度非常快,适用于高并发场景。缺点:
长度较长:UUID长度为128位,通常表示为36个字符(包括连字符),这在存储和传输时占用较多空间。例如,在数据库中存储UUID会比存储整数类型占用更多的空间。
无序性:UUID通常是随机生成的,缺乏时间上的顺序性。这在数据库索引中可能导致性能问题,因为插入操作可能需要在B树索引中频繁分裂节点。
可读性差:UUID对人类不友好,难以记忆和识别,不利于在用户界面或日志中直接使用。
缺乏业务相关性:UUID不包含任何业务信息,如时间戳或区域信息,难以用于业务分析和追踪。
- 适用场景
- 分布式系统:在多节点、多数据中心的环境中,UUID是生成唯一标识符的理想选择。
- 无需排序的场景:如果不需要按时间或其他顺序对ID进行排序,UUID是一个不错的选择。
- 高并发环境:UUID的生成速度非常快,适用于需要快速生成唯一标识符的高并发场景。
数据库自增ID是一种常见的生成唯一标识符的方法,通过在数据库表中设置自增字段(如
AUTO_INCREMENT),每次插入新记录时,数据库会自动为该字段生成一个唯一的、递增的整数。
优点:
简单易用:实现简单,只需在数据库表中设置自增字段,无需额外的代码或配置。
有序性:自增ID是有序的,有利于数据库索引的性能,特别是在使用B树索引时。
节省存储空间:整数类型的ID通常比UUID占用更少的存储空间。
可读性较好:整数ID对人类相对友好,易于识别和记忆。
缺点:
单点瓶颈:在分布式数据库环境中,自增ID难以保证全局唯一性,通常需要依赖单个数据库实例来生成ID,这会成为系统的单点瓶颈,影响性能和可扩展性。
难以水平扩展:如果系统需要水平扩展到多个数据库实例,自增ID的生成会成为问题,因为每个实例都会生成自己的ID序列,导致ID冲突。
依赖数据库:生成ID依赖于数据库,这在数据库故障或高负载时可能成为问题。
缺乏业务相关性:自增ID不包含任何业务信息,如时间戳或区域信息,难以用于业务分析和追踪。
- 适用场景
- 单体应用:在单体应用中,数据库自增ID是一个简单且有效的方法。
- 无需分布式唯一性的场景:如果系统不需要在多个数据库实例或多个数据中心中保持全局唯一性,自增ID是一个不错的选择。
- 对ID有序性有要求的场景:如果需要按时间或其他顺序对ID进行排序,自增ID的有序性是一个优势。
4.雪花算法的实现过程如下
获取当前时间戳,精确到毫秒级别。
根据给定的数据中心ID和机器ID,生成一个10位的二进制数。
将时间戳左移22位,将数据中心ID左移17位,将机器ID左移12位,然后使用位或操作符将它们组合成一个64位的二进制数。
如果在同一毫秒内生成了多个ID,使用序列号来区分它们,序列号从0开始递增,最多可以生成4096个序列号。
优点:全局唯一性:在分布式系统中,雪花算法可以确保生成的ID全局唯一。
有序性:生成的ID按照时间戳有序递增,便于数据管理和查询。
高并发:每毫秒可以生成4096个ID,适合高并发场景。
缺点:依赖服务器时间:如果服务器时间回拨,可能会导致生成重复的ID。可以通过记录最后一个生成ID的时间戳来解决这个问题。
序列号浪费:在分库分表时,如果序列号一直从0开始,可能会导致数据倾斜和不均匀分布。
`适用场景:分布式系统:如分布式数据库、分布式锁等,需要全局唯一且有序的ID。
高并发场景:如订单号生成、用户ID生成等
- 实现代码
public class SnowflakeIdGenerator {// 开始时间戳 (2023-01-01)private final long twepoch = 1672502400000L;// 机器ID所占的位数private final long workerIdBits = 5L;// 数据标识ID所占的位数private final long datacenterIdBits = 5L;// 支持的最大机器ID,结果是31 (这个值在位运算中不会溢出)private final long maxWorkerId = -1L ^ (-1L << workerIdBits);// 支持的最大数据标识ID,结果是31private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);// 序列号在ID中所占的位数private final long sequenceBits = 12L;// 机器ID需要左移的位数,12private final long workerIdShift = sequenceBits;// 数据标识ID需要左移的位数,17private final long datacenterIdShift = sequenceBits + workerIdBits;// 时间戳需要左移的位数,22private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;// 生成序列的掩码,这里为4095 (0b111111111111=4095)private final long sequenceMask = -1L ^ (-1L << sequenceBits);// 工作机器ID(0~31)private long workerId;// 数据中心ID(0~31)private long datacenterId;// 毫秒内序列(0~4095)private long sequence = 0L;// 上次生成ID的时间戳private long lastTimestamp = -1L;public SnowflakeIdGenerator(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}/*** 产生下一个ID*/public synchronized long nextId() {long timestamp = timeGen();// 如果当前时间小于上次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}// 如果是同一时间生成的,则进行毫秒内序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;// 毫秒内序列溢出if (sequence == 0) {// 阻塞到下一毫秒,获得新的时间戳timestamp = tilNextMillis(lastTimestamp);}} else {// 时间戳改变,毫秒内序列重置sequence = 0L;}// 上次生成ID的时间截lastTimestamp = timestamp;// 移位并通过或运算拼到一起组成64位的IDreturn ((timestamp - twepoch) << timestampLeftShift)| (datacenterId << datacenterIdShift)| (workerId << workerIdShift)| sequence;}protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}protected long timeGen() {return System.currentTimeMillis();}
}
相关文章:
SpringBoot生成唯一ID的方式
1.为什么要生成唯一ID? 数据唯一性:每个记录都需要有一个独一无二的标识符来确保数据的唯一性。这可以避免重复的数据行,并有助于准确地查询、更新或删除特定的记录。 数据完整性:通过使用唯一ID,可以保证数据库中的数…...
FastGPT 源码:RRF、Rerank 相关代码
文章目录 FastGPT 源码:RRF、Rerank 相关代码1. RRF (Reciprocal Rank Fusion) 合并实现2. Rerank 二次排序实现3. 重排序的主要特点4. 整个搜索流程5. 这种方式的优势 FastGPT 源码:RRF、Rerank 相关代码 下边介绍 RRF 合并和 Rerank 二次排序的相关实…...
Android视频流畅播放要素
要让 Android 设备流畅播放视频,需根据设备性能(低端、中端、高端)和播放场景(本地播放、在线流媒体)动态调整视频参数。以下是针对不同设备的推荐配置方案: 一、通用推荐配置(平衡兼容性与流畅…...
Python:类型转换和深浅拷贝,可变与不可变对象
int():转换为一个整数,只能转换由纯数字组成的字符串 浮点型强转整型会去掉小数点及后面的数,只保留整数部分 #如果字符串中有数字和正负号以外的字符就会报错 float():整形转换为浮点型会自动添加一位小数 .0 如果字符串中有…...
vcredist_x64 资源文件分享
vcredist_x64 是 Microsoft Visual C Redistributable 的 64 位版本,用于在 64 位 Windows 系统上运行使用 Visual C 开发的应用程序。它包含了运行这些应用程序所需的运行时组件。 vcredist_x64 资源工具网盘下载链接:https://pan.quark.cn/s/ef56f838f…...
Linux:vim快捷键
Linux打开vim默认第一个模式是:命令模式! 命令模式快捷键操作: gg:光标快速定位到最开始 shift g G:光标快速定位到最结尾 n shift g n G:光标快速定位到第n行 shift 6 ^:当前行开始 …...
DeepSeek在MATLAB上的部署与应用
在科技飞速发展的当下,人工智能与编程语言的融合不断拓展着创新边界。DeepSeek作为一款备受瞩目的大语言模型,其在自然语言处理领域展现出强大的能力。而MATLAB,作为科学计算和工程领域广泛应用的专业软件,拥有丰富的工具包和高效…...
NAT 代理服务 内网穿透
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 NAT 技术背景二:🔥 NAT IP 转换过程三:🔥 NAPT四:🔥 代理服务器🦋 正向…...
高级课第五次作业
首先配置交换机,路由器 LSW1配置 [SW1]vlan batch 10 20 30 40 [SW1]int g0/0/2 [SW1-GigabitEthernet0/0/2]port link-type access [SW1-GigabitEthernet0/0/2]port default vlan 10 [SW1]int g0/0/3 [SW1-GigabitEthernet0/0/3]port link-type access […...
51单片机编程学习笔记——动态数码管显示多个数字
大纲 视觉残留原理生理基础神经传导与处理 应用与视觉暂留相关的现象 频闪融合不好的实现好的效果 延伸 在《51单片机编程学习笔记——动态数码管》一文中,我们看到如何使用动态数码管显示数字。但是基于动态数码管设计的特点,每次只能显示1个数字。这就…...
金蝶ERP星空对接流程
1.金蝶ERP星空OPENAPI地址: 金蝶云星空开放平台 2.下载金蝶云星空的对应SDK包 金蝶云星空开放平台 3.引入SDK流程步骤 引入Kingdee.CDP.WebApi.SDK 右键项目添加引用,在打开的引用管理器中选择浏览页签,点击浏览按钮,找到从官…...
【随手笔记】利尔达NB模组
1.名称 移芯EC6263GPP 参数 指令备注 利尔达上电输出 [2025-03-04 10:24:21.379] I_AT_WAIT:i_len2 [2025-03-04 10:24:21.724] LI_AT_WAIT:i_len16 [2025-03-04 10:24:21.724] [2025-03-04 10:24:21.733] Lierda [2025-03-04 10:24:21.733] [2025-03-04 10:24:21.745] OK移…...
Vue3的核心语法【未完】
Vue3的核心语法 OptionsAPI与CompositionAPI Options API(选项式) 和 Composition API (组合式)是 Vue.js 中用于构建组件的两种不同方式。Options API Options API Options API 是 Vue 2 中的传统模式,并在 Vue 3…...
解决redis lettuce连接池经常出现连接拒绝(Connection refused)问题
一.软件环境 windows10、11系统、springboot2.x、redis 6 7 linux(centos)系统没有出现这问题,如果你是linux系统碰到的,本文也有一定大参考价值。 根本思路就是:tcp/ip连接的保活(keepalive)。 二.问题描述 在spr…...
C#进阶指南
C# 是一种功能强大的编程语言,其高级语法特性为开发者提供了更灵活、高效和简洁的编程方式。以下是一些常见的 C# 高级语法特性: 1. 委托(Delegate) 委托是一种类型安全的函数指针,用于封装方法的引用。它可以将方法作为参数传递,实现回调机制。 定义委托: csharp复制 …...
从DNS到TCP:DNS解析流程和浏览器输入域名访问流程
1 DNS 解析流程 1.1 什么是DNS域名解析 在生活中我们会经常遇到域名,比如说CSDN的域名www.csdn.net,百度的域名www.baidu.com,我们也会碰到IP,现在目前有的是IPV4,IPV6。那这两个有什么区别呢?IP地址是互联网上计算机…...
【MySQL、Oracle、SQLserver、postgresql】查询多条数据合并成一行
四大数据库多行合并为单行:函数详解与对比 一、MySQL**GROUP_CONCAT()** 函数说明:语法结构:参数解释:示例:注意事项: 二、Oracle**LISTAGG()** 函数说明:语法结构:参数解释…...
解锁Egg.js:从Node.js小白到Web开发高手的进阶之路
一、Egg.js 是什么 在当今的 Web 开发领域,Node.js 凭借其事件驱动、非阻塞 I/O 的模型,在构建高性能、可扩展的网络应用方面展现出独特的优势 ,受到了广大开发者的青睐。它让 JavaScript 不仅局限于前端,还能在服务器端大展身手&…...
JavaWeb后端基础(4)
这一篇就开始是做一个项目了,在项目里学习,我主要记录在学习过程中遇到的问题,以及一些知识点 Restful风格 一种软件架构风格 在REST风格的URL中,通过四种请求方式,来操作数据的增删改查。 GET : 查询 …...
软件试用 防破解 防软件调试(C# )
防破解&防软件调试 实现思路 这里采用C#语言为例: 获取网络北京时间:向百度发送 HTTP 请求,从响应头中提取日期时间信息,将其转换为本地时间。记录试用开始时间:首次运行软件时,将获取的百度北京时间作为试用开始时间,并加密存储在本地文件中。检查试用是否过期:每…...
【文献阅读】The Efficiency Spectrum of Large Language Models: An Algorithmic Survey
这篇文章发表于2024年4月 摘要 大语言模型(LLMs)的快速发展推动了多个领域的变革,重塑了通用人工智能的格局。然而,这些模型不断增长的计算和内存需求带来了巨大挑战,阻碍了学术研究和实际应用。为解决这些问题&…...
OpenGL ES -> GLSurfaceView纹理贴图
贴图 XML文件 <?xml version"1.0" encoding"utf-8"?> <com.example.myapplication.MyGLSurfaceViewxmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height…...
FastGPT 源码:基于 LLM 实现 Rerank (含Prompt)
文章目录 基于 LLM 实现 Rerank函数定义预期输出实现说明使用建议完整 Prompt 基于 LLM 实现 Rerank 下边通过设计 Prompt 让 LLM 实现重排序的功能。 函数定义 class LLMReranker:def __init__(self, llm_client):self.llm llm_clientdef rerank(self, query: str, docume…...
DE2115实现4位全加器和3-8译码器(FPGA)
一、配置环境 1、Quartus 18.1安装教程 软件:Quartus版本:Quartus 18.1语言:英文大小:5.78G安装环境:Win11/Win10/Win8/Win7硬件要求:CPU2.0GHz 内存4G(或更高) 下载通道①百度网盘丨64位下载…...
大语言模型(LLM)如何赋能时间序列分析?
引言 近年来,大语言模型(LLM)在文本生成、推理和跨模态任务中展现了惊人能力。与此同时,时间序列分析作为工业、金融、物联网等领域的核心技术,长期依赖传统统计模型(如ARIMA)或深度学习模型&a…...
【AI大模型】DeepSeek + Kimi 高效制作PPT实战详解
目录 一、前言 二、传统 PPT 制作问题 2.1 传统方式制作 PPT 2.2 AI 大模型辅助制作 PPT 2.3 适用场景对比分析 2.4 最佳实践与推荐 三、DeepSeek Kimi 高效制作PPT操作实践 3.1 Kimi 简介 3.2 DeepSeek Kimi 制作PPT优势 3.2.1 DeepSeek 优势 3.2.2 Kimi 制作PPT优…...
如何快速上手RabbitMQ 笔记250304
如何快速上手RabbitMQ 要快速上手 RabbitMQ,可以按照以下步骤进行,从安装到基本使用逐步掌握核心概念和操作: 1. 理解核心概念 Producer(生产者):发送消息的程序。Consumer(消费者)…...
run方法执行过程分析
文章目录 run方法核心流程SpringApplicationRunListener监听器监听器的配置与加载SpringApplicationRunListener源码解析实现类EventPublishingRunListener 初始化ApplicationArguments初始化ConfigurableEnvironment获取或创建环境配置环境 打印BannerSpring应用上下文的创建S…...
面试-----每日一题
一、字节一面(操作系统) 什么是死锁?如何处理死锁问题? 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通讯而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。…...
学习与事务平衡技巧
当学习过程中需要处理其他事务时,关键在于平衡专注与灵活性,避免中断打乱学习节奏。以下是具体建议: 一、快速判断事务优先级 紧急且重要(如突发工作、紧急回复): 立刻处理,但完成后用5分钟快速…...
