分布式系统中雪花ID的使用及前后台精度解决

  本文介绍了雪花ID的应用场景,以及针对雪花id生成精度过大导致数据缺失的解决方案。

一、概念

       雪花 ID是一种分布式 ID 生成策略,保证全局唯一,位数组成中含有时间戳,相比UUID,故也能保证自增。

二、应用场景

分库、分表、分片、中间件集群部署、数据合并中,

如果使用自增id,易造成冲突

三、实现方式

1、生成雪花id算法

SnowflakeIdGenerator.java

package com.inspur.common.utils;import org.springframework.beans.factory.annotation.Value;public class SnowflakeIdGenerator {@Value("${snowflake.dataCenterId}")private static long dataCenterId;// 数据中心ID(可根据实际情况配置)@Value("${snowflake.machineId}") // 机器ID(可根据实际情况配置)private static long machineId;// 起始的时间戳,可以根据实际情况调整private static final long START_TIMESTAMP = 1609459200000L; // 2021-01-01 00:00:00// 每部分占用的位数private static final long SEQUENCE_BIT = 10; // 序列号占用的位数private static final long MACHINE_BIT = 1;   // 机器标识占用的位数private static final long DATA_CENTER_BIT = 1; // 数据中心标识占用的位数// 每部分的最大值private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_BIT);private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_BIT);// 每部分向左的位移private static final long MACHINE_LEFT = SEQUENCE_BIT;private static final long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private static final long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;/*// 数据中心ID(可根据实际情况配置)private final long dataCenterId;// 机器ID(可根据实际情况配置)private final long machineId;*/// 序列号private long sequence = 0L;// 上次生成ID的时间戳private long lastTimestamp = -1L;/*** 初始化 SnowflakeIdGenerator 对象,并设置数据中心标识和机器标识* @param dataCenterId 数据中心标识* @param machineId 机器标识*/public SnowflakeIdGenerator(long dataCenterId , long machineId) {if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) { // 进行合法性检查,确保传入的数据中心标识和机器标识在合理范围内,否则抛出 IllegalArgumentException。throw new IllegalArgumentException("Data center ID can't be greater than " + MAX_DATA_CENTER_ID + " or less than 0");}if (machineId > MAX_MACHINE_ID || machineId < 0) {throw new IllegalArgumentException("Machine ID can't be greater than " + MAX_MACHINE_ID + " or less than 0");}this.dataCenterId = dataCenterId;this.machineId = machineId;}/*** 生成雪花算法的唯一ID* @return 最终的64位ID*///确保在多线程环境下生成的ID是唯一的,防止并发冲突。如果您的应用是单线程或者在多线程环境下并发要求不高,可以适当简化同步逻辑。public synchronized long generateId() {long currentTimestamp = System.currentTimeMillis(); // 获取当前时间戳 currentTimestamp,以毫秒为单位。if (currentTimestamp < lastTimestamp) { // 检查当前时间戳是否小于上一次生成ID的时间戳 lastTimestamp,如果是,说明发生了时钟回拨,抛出 RuntimeException。throw new RuntimeException("Clock moved backwards. Refusing to generate ID for " + (lastTimestamp - currentTimestamp) + " milliseconds.");}if (currentTimestamp == lastTimestamp) { // 如果当前时间戳与上一次时间戳相等,则递增序列号 sequence,并通过位运算确保序列号不超过最大值。如果序列号归零,表示在同一毫秒内生成的ID数量超过限制,调用 waitNextMillis 方法等待下一毫秒。sequence = (sequence + 1) & MAX_SEQUENCE;if (sequence == 0) {currentTimestamp = waitNextMillis(currentTimestamp);}} else {sequence = 0L; // 如果当前时间戳大于上一次时间戳,将序列号重置为零。}lastTimestamp = currentTimestamp;/* System.out.println( ((currentTimestamp) << TIMESTAMP_LEFT) |(dataCenterId << DATA_CENTER_LEFT) |(machineId << MACHINE_LEFT) |sequence);*/// 将当前时间戳、数据中心标识、机器标识和序列号按照雪花算法的规则组合起来,生成最终的64位ID。return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_LEFT) |(dataCenterId << DATA_CENTER_LEFT) |(machineId << MACHINE_LEFT) |sequence;}/*** 时钟回拨策略:发生时钟回拨时等待下一个合适的时间戳。* @param currentTimestamp 方法被调用时的当前时间戳* @return 返回新的时间戳,以确保生成的ID是在递增的时间戳基础上生成的。*/private long waitNextMillis(long currentTimestamp) {long timestamp = System.currentTimeMillis();// 判断 timestamp 是否小于等于上一次生成ID的时间戳 lastTimestamp。如果是,说明当前时间戳仍然没有超过上一次生成ID的时间戳,继续在循环内等待。while (timestamp <= lastTimestamp) {timestamp = System.currentTimeMillis(); // 不断更新 timestamp 为当前时间戳,直到 timestamp 大于 lastTimestamp。}return timestamp; // 返回新的时间戳,以确保生成的ID是在递增的时间戳基础上生成的。}public synchronized static long getId() {SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(dataCenterId, machineId);return idGenerator.generateId();}public static void main(String[] args) {// 根据情况决定long dataCenterId = 1L;  // 数据中心标识long machineId = 1L;     // 机器标识SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(dataCenterId, machineId);// 使用 idGenerator 生成唯一IDlong uniqueId = idGenerator.generateId();System.out.print(String.valueOf(uniqueId));}}

2、应用

(1) 插入语句
objectPo.setId(SnowflakeIdGenerator.getId());
objectPo.setCreateTime(DateUtils.getNowDate());
int i = objectPoMapper.insertObjectPo(objectPoReason);
(2) Mapper层
insert into objectPo_table_name
<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null and id != ''">id,</if><if test="createTime != null">create_time,</if><if test="其他 != null">...</if></trim>
<trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null and id != ''">#{id},</if><if test="createTime != null">#{createTime},</if><if test="其他!= null">#{其他},</if></trim>

四、前后台精度缺失问题

      由于雪花算法长度较大,前端接收数据类型为number类型 , 最大为16位, 如果后端 id 大于16位, 则会出现 精度丢失问题, 如雪花算法 id 为18位就会造成精度缺失。

       可以缩短雪花生成算法中的工作机器位数和序列号位数; 或者将id添加添加一个数据类型转换器后台传至前台时Long型转为String, 前台传至后台时String转为Long。

1、后台序列化

实体类的id或者引用存储其他表id的字段,加上:

@JsonSerialize(using = ToStringSerializer.class)private Long id;@JsonSerialize(using = ToStringSerializer.class)private Long relaTableId;

2、前台number

取消Number()函数使用。

3、jsonBig转化

如果存储的json数据含有雪花id, 在JSON字符串转化实体类时,注意:

JSON.parse(jsonString)会造成精度丢失,用JSONBig.parse(jsonString)取代。

npm install json-bigintimport JSONBig from 'json-bigint'

4、雪花id生成位数

在雪花id生成算法中(SnowflakeIdGenerator.java),适当缩小工作机器位数和序列号位数。

如:

MACHINE_BITDATA_CENTER_BIT

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

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

相关文章

【windows OBS开启直播】Windows搭建RTMP视频流服务(Nginx服务器版)

如果您想在windows 电脑上设置RTMP服务器&#xff0c;并使用VLC播放器播放OBS的直播流&#xff0c;您可以使用一个本地的RTMP服务器软件&#xff0c;如nginx配合nginx-rtmp-module来搭建。下面 详细介绍下如何搭建此视频流服务。 1、安装和配置本地RTMP服务器 步骤1&#xff…

ST Smart Things Sentinel:一款针对复杂IoT协议的威胁检测工具

关于ST Smart Things Sentinel ST Smart Things Sentinel&#xff0c;简称ST&#xff0c;是一款功能强大的安全工具&#xff0c;广大研究人员可以使用该工具检测物联网 (IoT) 设备使用的复杂协议中的安全威胁。 在不断发展的联网设备领域&#xff0c;ST Smart Things Sentinel…

matlab入门学习

一、什么是matlab MATLAB&#xff08;matrix laboratory矩阵实验室&#xff09;是一款商用数学软件&#xff0c;主要面对科学计算、可视化以及交互式程序设计的高科技计算环境。可用于数据分析、深度学习、图像处理与计算机视觉、量化金融与风险管理等领域。 二、matlab和pyt…

WEB07Vue+Ajax

1. Vue概述 Vue&#xff08;读音 /vjuː/, 类似于 view&#xff09;&#xff0c;是一款用于构建用户界面的渐进式的JavaScript框架&#xff08;官方网站&#xff1a;https://cn.vuejs.org&#xff09;。 在上面的这句话中呢&#xff0c;出现了三个词&#xff0c;分别是&#x…

宝兰德参编金融智能体标准,深耕大模型场景化落地

随着数智化浪潮的不断推进&#xff0c;人工智能技术正深刻影响着金融服务的模式和流程&#xff0c;金融智能体在大模型的加持下&#xff0c;业务场景的应用能力得到强化。然而&#xff0c;作为新型技术&#xff0c;金融智能体在隐私保护、透明性、数据泄露等方面仍存在诸多风险…

枸杞糖基转移酶--文献精读31

Functional and structural dissection of glycosyltransferases underlying the glycodiversity of wolfberry-derived bioactive ingredients lycibarbarspermidines 功能和结构分析导致枸杞来源的生物活性成分&#xff08;如lycibarbarspermidines类化合物&#xff09;糖基…

C++入门基础知识2

1.引用 1.1引用的使用 1.引用在实践中主要是引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象 2.引用传参跟指针传参功能是类似的&#xff0c;引用传参相对更方便一些 3.引用和指针在实践中相辅相成&#xff0c;功能有重叠性&#xff0c;各有特…

嵌入式C++、Qt/QML和MQTT:智能工厂设备监控系统的全流程介绍(附代码示例)

1. 项目概述 本项目旨在开发一套先进的智能工厂设备监控系统&#xff0c;集成嵌入式技术、工业通信协议和人机界面等多项技术&#xff0c;实现对工厂设备的全方位实时监控、高精度数据采集和智能化分析。该系统将显著提升工厂设备的运行效率&#xff0c;大幅降低维护成本&…

基于AT89C51单片机的16×16点阵LED显示器字符滚动显示设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的1616点阵LED显示器字符滚动显示设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 仿真效果图 仿真图 代码 系统论文 资源下载 设计的内容和要求 熟悉51系…

Python练习题(3)

1.使用requests模块获取这个json文件http://java-api.super-yx.com/html/hello.json 2.将获取到的json转为dict 3.将dict保存为hello.json文件 4.用文件流写一个copy(src,dst)函数,复制hello.json到C:\hello.json import requests import jsondef copy(src, dst):read_file o…

【typedb】例子:药物发现 1: 模式导入

typedb-examples/drug-discovery/ Drug discovery监听0.0.0.0:1729 但这么连接肯定不行: localhost:1729 可以: 一直无法点击schema图标:先创建一个数据库 选中数据库: 选中后就可以了:

我的第128天创作纪念日

&#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;初阶数据结构笔记专栏&#xff1a; 初阶数据结构笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自踏雪至山巅 文章…

演示:【Avalonia-Controls】Avalonia皮肤,主题,自定义控件,数据库,系统模块资源库

一、目的&#xff1a;分享一个Avalonia皮肤&#xff0c;主题&#xff0c;自定义控件&#xff0c;数据库&#xff0c;系统模块资源库 开源地址&#xff1a; GitHub - HeBianGu/Avalonia-Controls: Avalonia控件库 Nuget包地址&#xff1a; NuGet Gallery | Packages matchin…

02MFC画笔/画刷/画椭圆/圆/(延时)文字

文章目录 画实心矩形自定义画布设计及使用连续画线及自定义定义变量扇形画椭圆/圆输出颜色文本定时器与定时事件 画实心矩形 自定义画布设计及使用 连续画线及自定义定义变量 扇形 画椭圆/圆 输出颜色文本 定时器与定时事件

大模型时代的目标检测

https://zhuanlan.zhihu.com/p/663703934https://zhuanlan.zhihu.com/p/6637039341.open set/open word/ood 这个任务是指在实际应用上可以检测任何前景物体&#xff0c;但是有些不需要预测类别&#xff0c;只要检测出框就行。在很多场合也有应用场景&#xff0c;有点像类无关…

力扣 爬楼梯

动态规划算法基础篇。 class Solution {public int climbStairs(int n) {int[] f new int[n 1];f[0] 1;f[1] 1;//当爬到n阶楼梯时&#xff0c;可知是由n-1阶或n-2阶楼梯而来for(int i 2; i < n; i) {f[i] f[i - 1] f[i - 2];//后面的每一阶种数由前两个状态得到}ret…

Milvus 核心设计 (3) ---- metric及index原理详解与示例(1)

目录 背景 Floating point embeddings 特点 适用场景 丈量方式 Euclidean distance (L2) Inner product (IP) Cosine similarity (COSINE) 代码写法 索引类型 In-Memory FLAT 索引 IVF_FLAT IVF_FLAT的工作流程 平衡准确性与速度 性能考虑 代码写法 IVF_SQ8 …

栈和队列 OJ (一)

括号匹配问题 题目链接&#xff1a; https://leetcode.cn/problems/valid-parentheses/ 遇到左括号入栈&#xff0c;遇到右括号&#xff0c;我们就出栈看看括号是否匹配 这里要注意如果左括号多于右括号的情况下&#xff0c;字符串循环遍历结束时&#xff0c;栈不为空&#x…

Android --- Kotlin学习之路:自己写一个SDK给别的APP用(暴漏一个接口,提供学生的身高数据)

今天又来肝kotlin了&#xff0c;主题是&#xff1a;用kt写一个SDK给其他人用&#xff0c;这个小技能在项目中会经常用到&#xff0c;应该有很多小伙伴还不会用&#xff0c;不会的请往下看—⬇ 在项目里面新建一个module 选择Android library&#xff0c;然后点击finish就行了 …

【Java】二维数组

文章目录 一、什么是二维数组二、二维数组的声明形式三、二维数组的创建(1)静态初始化(2)动态初始化 四、二维数组的输入五、二维数组在内存中的存储方式 一、什么是二维数组 一维数组的声明是int[] arr&#xff0c;int[] arr {0,1,2,3,…};通过一维数组的形式和表达式 我们…