Java 生成的 UUID 出现了重复?! 什么鬼?? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yuhuan66666
V2EX    Java

Java 生成的 UUID 出现了重复?! 什么鬼??

  •  
  •   yuhuan66666 2017-05-22 13:13:17 +08:00 21984 次点击
    这是一个创建于 3067 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不是号称 比被陨石砸中都的概率还小么。。。。。

    怎么当一年的主键就重复了好几个呢。。。。

    各位大大 都用啥当主键的?

    难不成真要 各个字段连成一条+UUID 生成的字符串,再算成 SHA512 当主键吗???

    太复杂了吧。。。。

    第 1 条附言    2017-05-22 14:09:51 +08:00
    用的就是 UUID.randomUUID()方法生成的 UUID
    第 2 条附言    2017-05-22 15:58:38 +08:00
    请问使用 java 怎样可以生成一个时间基于时间的唯一性 UUID 呢 我现在用的全是版本 4 的
    27 条回复    2017-07-12 00:10:20 +08:00
    knightdf
        1
    knightdf  
       2017-05-22 13:28:48 +08:00
    没人说不重复啊。。。
    lonenol
        2
    lonenol  
       2017-05-22 13:30:33 +08:00
    各种算法一大堆,随便 Goolebaidubing 一下
    congeec
        3
    congeec  
       2017-05-22 13:34:18 +08:00
    出现重复的就二次 hash 呗
    oh
        4
    oh  
       2017-05-22 13:34:33 +08:00 via iPhone
    好想知道楼主的业务一年业务量是多少,出现了好几条重复
    watzds
        5
    watzds  
       2017-05-22 13:36:48 +08:00 via Android
    也可能代码有 bug
    wu1990
        6
    wu1990  
       2017-05-22 13:38:14 +08:00
    数据量多大
    zjsxwc
        7
    zjsxwc  
       2017-05-22 13:38:33 +08:00
    只能相对地说不会重复,具体还是要看使用环境:
    https://zhihu.com/question/34876910/answer/88924223
    honeycomb
        8
    honeycomb  
       2017-05-22 13:38:49 +08:00 via Android
    你是生成了哪种 UUID ?
    类型 1 还是类型 4 ?

    类型 4 是全随机的,要考虑随机数生成器的用法有没有问题。
    类型 1 和时间有关,每秒钟有 1630 亿个可用。
    nanpuyue
        9
    nanpuyue  
       2017-05-22 13:39:04 +08:00   3
    楼主你出门可要小心天上的陨石了~
    tomczhen
        11
    tomczhen  
       2017-05-22 13:48:27 +08:00 via iPhone
    uuid 也分好几种的,而且多线程并行生成不用一些方法的话也有生成相同 uuid 的可能。
    bozong
        12
    bozong  
       2017-05-22 13:56:35 +08:00
    Tb 级别数据量?
    ytmsdy
        13
    ytmsdy  
       2017-05-22 14:01:22 +08:00
    快去买彩票!
    yuhuan66666
        14
    yuhuan66666  
    OP
       2017-05-22 14:10:11 +08:00
    @honeycomb #8 用的最简单的 UUID.randomUUID()生成的
        15
    icedx  
       2017-05-22 14:11:39 +08:00
    和时间戳绑定一下就好了
    xmh51
        16
    xmh51  
       2017-05-22 14:22:35 +08:00
    多线程 下 使用?
    jason19659
        17
    jason19659  
       2017-05-22 14:35:12 +08:00
    找个按照时间戳生成的工具类
    angelface
        18
    angelface  
       2017-05-22 14:41:41 +08:00
    @yuhuan66666 Type 4 类的是随机数,是有可能重复的。可以换一个 Time-Based 的工具包。
    magicdawn
        19
    magicdawn  
       2017-05-22 14:43:38 +08:00
    ooTwToo
        20
    ooTwToo  
       2017-05-22 14:53:55 +08:00
    试试 twitter 的 snowflake
    honeycomb
        21
    honeycomb  
       2017-05-22 16:16:36 +08:00
    用版本 1 就可以了

    看到一个类似例子:
    http://bbs.csdn.net/topics/390434666

    按理说 getUUID 背后用的是 UUID 类里一个静态 SecureRandom,随机数的来源是 SecureRandom.nextBytes,不该出现重复问题
    yuhuan66666
        22
    yuhuan66666  
    OP
       2017-05-22 16:53:00 +08:00
    @honeycomb #21 请问 怎么才能生成版本 1 的 UUID 呢 我看 java API 没提供对应的方法
    momocraft
        23
    momocraft  
       2017-05-22 17:22:27 +08:00
    @honeycomb "Secure" 的要求是无法预测。在长度有限时要求不重复是不现实的。
    superadmin
        24
    superadmin  
       2017-05-22 17:41:46 +08:00
    Twitter-Snowflake
    参考:
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    /**
    * tweeter 的 snowflake 移植到 Java:
    * (a) id 构成: 42 位的时间前缀 + 10 位的节点标识 + 12 位的 sequence 避免并发的数字(12 位不够用时强制得到新的时间前缀)
    * 注意这里进行了小改动: snowkflake 是 5 位的 datacenter 加 5 位的机器 id; 这里变成使用 10 位的机器 id
    * (b) 对系统时间的依赖性非常强,需关闭 ntp 的时间同步功能。当检测到 ntp 时间调整后,将会拒绝分配 id
    */

    public class IdWorker {

    private final static Logger logger = LoggerFactory.getLogger(IdWorker.class);

    private final long workerId;
    private final long epoch = 1403854494756L; // 时间起始标记点,作为基准,一般取系统的最近时间
    private final long workerIdBits = 10L; // 机器标识位数
    private final long maxWorkerId = -1L ^ -1L << this.workerIdBits;// 机器 ID 最大值: 1023
    private long sequence = 0L; // 0,并发控制
    private final long sequenceBits = 12L; //毫秒内自增位

    private final long workerIdShift = this.sequenceBits; // 12
    private final long timestampLeftShift = this.sequenceBits + this.workerIdBits;// 22
    private final long sequenceMask = -1L ^ -1L << this.sequenceBits; // 4095,111111111111,12 位
    private long lastTimestamp = -1L;

    private IdWorker(long workerId) {
    if (workerId > this.maxWorkerId || workerId < 0) {
    throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", this.maxWorkerId));
    }
    this.workerId = workerId;
    }

    public synchronized long nextId() throws Exception {
    long timestamp = this.timeGen();
    if (this.lastTimestamp == timestamp) { // 如果上一个 timestamp 与新产生的相等,则 sequence 加一(0-4095 循环); 对新的 timestamp,sequence 从 0 开始
    this.sequence = this.sequence + 1 & this.sequenceMask;
    if (this.sequence == 0) {
    timestamp = this.tilNextMillis(this.lastTimestamp);// 重新生成 timestamp
    }
    } else {
    this.sequence = 0;
    }

    if (timestamp < this.lastTimestamp) {
    logger.error(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", (this.lastTimestamp - timestamp)));
    throw new Exception(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", (this.lastTimestamp - timestamp)));
    }

    this.lastTimestamp = timestamp;
    return timestamp - this.epoch << this.timestampLeftShift | this.workerId << this.workerIdShift | this.sequence;
    }

    private static IdWorker flowIdWorker = new IdWorker(1);
    public static IdWorker getFlowIdWorkerInstance() {
    return flowIdWorker;
    }



    /**
    * 等待下一个毫秒的到来, 保证返回的毫秒数在参数 lastTimestamp 之后
    */
    private long tilNextMillis(long lastTimestamp) {
    long timestamp = this.timeGen();
    while (timestamp <= lastTimestamp) {
    timestamp = this.timeGen();
    }
    return timestamp;
    }

    /**
    * 获得系统当前毫秒数
    */
    private static long timeGen() {
    return System.currentTimeMillis();
    }

    public static void main(String[] args) throws Exception {
    System.out.println(timeGen());

    IdWorker idWorker = IdWorker.getFlowIdWorkerInstance();
    // System.out.println(Long.toBinaryString(idWorker.nextId()));
    System.out.println(idWorker.nextId());
    System.out.println(idWorker.nextId());
    }

    }
    aksoft
        25
    aksoft  
       2017-05-23 08:32:14 +08:00
    啥事也没有绝对的
    julyclyde
        26
    julyclyde  
       2017-05-23 14:58:15 +08:00
    只要数量有限,那将来必然重复
    无非你比别人早点碰上了而已,有啥好大惊小怪的
    xufeng
        27
    xufeng  
       2017-07-12 00:10:20 +08:00
    重复的概率确实有,如果你的数据量不大,那么应该考虑你的代码是否有问题。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2791 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 14:50 PVG 22:50 LAX 07:50 JFK 10:50
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86