项目中数据库会生成不重复随机数主键ID,但是不适合生成订单号。因此要自己写随机订单号。考虑采用雪花算法。
先写一个生成订单的工具类,然后再写一个调用工具类调用先前工具类生成ID的方法。
package com.rdd;
* Twitter_Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
* 加起来刚好64位,为一个Long型。<br>
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
public class UniqueOrderGenerate {
// ==============================Fields===========================================
/** 开始时间截 (2018-07-03) */
private final long twepoch = 1530607760000L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 支持的最大数据标识id,结果是31 */
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdBits;
/** 时间截向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=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;
//==============================Constructors=====================================
* 构造函数
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
public UniqueOrderGenerate(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;
// ==============================Methods==========================================
* 获得下一个ID (该方法是线程安全的)
* @return SnowflakeId
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位的ID
return (((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence);
* 阻塞到下一个毫秒,直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
return timestamp;
* 返回以毫秒为单位的当前时间
* @return 当前时间(毫秒)
protected long timeGen() {
return System.currentTimeMillis();
//==============================Test=============================================
/** 测试 */
public static void main(String[] args) {
UniqueOrderGenerate idWorker = new UniqueOrderGenerate(0, 0);
for (int i = 0; i < 1000; i++) {
long id = idWorker.nextId();
//System.out.println(Long.toBinaryString(id));
System.out.println(id);
public class RecordNoUtils {
//这里的0,0分别是 * @param workerId 工作ID (0~31) * @param datacenterId 数据中心ID (0~31),可以写在配置文件中。
private static UniqueOrderGenerate idWorker = new UniqueOrderGenerate(0, 0);
public static RecordNoUtils getInstance() {
return new RecordNoUtils();
public long get() {
return idWorker.nextId();
转载:https://blog.csdn.net/Dongguabai/article/details/83692012
转载:https://blog.csdn.net/qq_38366063/article/details/83691424
原文链接:https://blog.csdn.net/qq_38366063/article/details/83691424
最近公司正好在做数据库迁移从oracle到mysql,因为之前oracle主键是使用的 SYS_GUID () 这个oracle提供的函数来生成全球唯一的标识符(原始值)由16个字节组成。可是由于mysql默认使用的InnoDB存储引擎采用的聚簇索引,使用uuid对写性能有一定的影响。而且为了后续分库分表考虑,也不宜采用数据库自增,因此就考虑到需要使用一种可以支持分布式递增且全局唯一的Id生成算...
一:概述-SnowFlake 算法-是 Twitter 开源的分布式 id 生成算法。- 应用场景- 高性能的产生不重复ID,支持集群的横向扩展。二:原理-其核心思想就是:-使用一个 64 bit 的 long 型的数字作为全局唯一 id。-在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的。- 产生公式-| 0(最高位预留) | 时间戳(41位) | 机器ID(10位...
snowflake的结构如下(每部分用-分开):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以使用69年),然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Map;
import jav
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的,作为索引非常不好,严重影响性能。
snowflake的结构如下(每部分用-分开):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - ...
snowflake 中文的意思是雪花,所以常被称为雪花算法。SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。
* Twitter_Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 00000000000...
* Twitter_Snowflake
* SnowFlake的结构如下(每部分用-分开):
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是
原文链接:
雪花算法(snowflake)生成Id重复问题 - 简书前言 最近工作上遇到一个雪花算法生成Id重复导致数据库中表主键冲突,导致入库失败的问题,所以顺便学习了一下雪花算法,下面是学习的笔记以及讨论如果解决雪花算法在分布式部署中生成...https://www.jianshu.com/p/71286e89e0c5
最近工作上遇到一个雪花算法生成Id重复导致数据库中表主键冲突,导致入库失败的问题,所以顺便学习了一下雪花算法,下面是学习的笔记以及讨论如果解决雪花算法在分布式部署中生成重复I
是什么雪花算法 (SnowFlake )算法,是 Twitter 开源的分布式 id 生成算法。有这么一种说法,自然界中并不存在两片完全一样的雪花的。每一片雪花都拥有自己漂亮独特的形状、独一无二。雪花算法也表示生成的ID如雪花般独一无二。其核心思想是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的。这 64 个...
工作中难免会碰到要生成一个不重复的数字来充当id的需求,这时候你会怎么办,使用UUID?还是使用当前时间节点拼接随机数?今天就来为大家推荐一个非常好用的算法:雪花算法。
雪花算法: 是由符号位+时间戳+工作机器id+序列号组成的,如图所示:
符号位为0,0表示正数,ID为正数。
时间戳位不用多说,用来存放时间戳,单位是ms。
工作机器id位用来存放机器的id,通常分为5个区域位+5个服务器标识位。
序号位是自增。
雪花算法能存放多少数据?时间范围:2^41 / (3652460601000)
雪花算法是Twitter开源的分布式ID生成算法。
雪花算法使用一个64bit的long型的数字作为全局唯一ID。在分布式系统中的应用十分广泛,且ID引入了时间戳,基本上保持自增的。
64bit的long型数字组成如下:
第一部分:1bit,0,无意义的数字
因为二进制里第一个bit如果为1,那么都是负数,但是我们生成的ID都是正数,所以第一个bit统一都是0
第二部分:41bit,表示的是时间戳
毫秒的时间戳,41bit可以表示的数字多达2^41-1个毫秒值,换成年就是表示69年的时间
背景:解决分布式自增ID发生碰撞问题。挺简单的。采用64位的Long类型数据,而不是uuid类型的。 优点:可以根据自己的业务需要进行修改。参考博客:http://yuanhsh.iteye.com/blog/2209696https://www.cnblogs.com/relucent/p/4955340.html以下纯属代码了,不喜者勿进public class Snowflak...
可以直接使用的雪花算法生成工具类
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
* Twrite雪花算法,生成不重复的UUID
* by liangguangjie
public class SnowflakeIdWorker {
// ==============================Fields=======================
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。
这种方案大致来说是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案把64-bit分别划分成多段,分开来标示机器、时间等。
其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),1...