randomUUID 是否给出唯一的 id?

问题描述 投票:0回答:5

我正在尝试为我的 REST API 创建会话令牌。每次用户登录时,我都会通过

创建一个新令牌
UUID token = UUID.randomUUID();
user.setSessionId(token.toString());
Sessions.INSTANCE.sessions.put(user.getName(), user.getSessionId());

但是,我不确定如何防止重复的 sessionToken。

例如:是否存在这样一种场景:user1 登录并获得令牌

87955dc9-d2ca-4f79-b7c8-b0223a32532a
,而 user2 登录并 获得令牌
87955dc9-d2ca-4f79-b7c8-b0223a32532a

有更好的方法吗?

java random uuid
5个回答
86
投票

如果遇到UUID冲突,接下来就去玩抽奖。

来自维基百科:

随机生成的 UUID 有 122 个随机位。总共 128 个中 位,四位用于版本(“随机生成的 UUID”), 和两个变体位('Leach-Salz')。

使用随机 UUID, 两个具有相同值的机会可以使用以下公式计算 概率论(生日悖论)。使用近似值

p(n)\approx 1-e^{-\tfrac{n^2}{{2x}}}

这些是概率 计算 n 个 UUID 后发生意外冲突,其中 x=2122:

n 概率 68,719,476,736 = 236 0.0000000000000004 (4 × 10−16) 2,199,023,255,552 = 241 0.0000000000004 (4 × 10−13) 70,368,744,177,664 = 246 0.0000000004 (4 × 10−10)

为了正确看待这些数字, 据估计,每年有人被陨石击中的风险是 170 亿分之一的机会,这意味着概率约为 0.00000000006 (6 × 10−11),相当于一年内创建数十万亿个 > UUID 并且有一个重复的几率。在 换句话说,只有在每秒生成 10 亿个 UUID 后 未来 100 年,仅创建一个副本的概率 大约是50%。出现一个重复的概率约为 如果地球上每个人都拥有 6 亿个 UUID,则为 50%。


16
投票

由于 UUID 的大小有限,因此它不可能在所有空间和时间上都是唯一的。

如果您需要保证在任何合理用例中唯一的 UUID,您可以使用 Log4j 2 的 Uuid.getTimeBasedUuid()。只要您每毫秒生成的 UUID 少于 10,000 个,它就可以保证在大约 8,900 年中保持唯一。


8
投票

Oracle UUID 文档。 http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html

他们使用互联网工程任务组的算法。 http://www.ietf.org/rfc/rfc4122.txt

摘自摘要。

UUID 长度为 128 位,可以保证跨区域的唯一性 空间和时间。

虽然摘要声称有保证,但只有

3.4 x 10^38
组合。 CodeChimp


1
投票

来自

UUID.randomUUID()
Javadoc:

用于检索类型 4(伪随机生成)UUID 的静态工厂。 UUID 是使用加密的强伪随机数生成器生成的。

它是随机的,因此肯定会发生碰撞,正如上面/下面的评论中其他人很早就检测到碰撞所证实的那样。 我建议您使用版本 1(基于时间),而不是版本 4(基于随机)。

可能的解决方案:

1) Log4j 的 UUID 实用程序

您可以使用 Log4j

UuidUtil.getTimeBasedUuid()
中的第 3 方实现,该实现基于当前时间戳(从 1582 年 10 月 10 日起以 100 纳秒为单位进行测量),并与创建 UUID 的设备的 MAC 地址连接起来。请参阅工件
log4j-core
中的包 org.apache.logging.log4j.core.util

2) FasterXML 的 UUID 实用程序

FasterXML 也有基于时间和 MAC 地址的第 3 方实现。请参阅工件

java-uuid-generator
中的包
Generators.timeBasedGenerator().generate()

3)自己做

或者您可以使用核心 Java 中的构造函数

com.fasterxml.uuid

来实现您自己的。请参阅以下非常好的解释

Baeldung - Java 中的 UUID 指南
,其中在实现中使用了 1582 年 10 月 15 日(实际上是非常著名的一天)。


0
投票
绝对100%确定

不会有重复项,只需创建一个TokenHandler即可。它所需要的只是一个生成随机 UUID 的同步方法,循环遍历已创建的每个 UUID(当然,时间效率不是很高,但如果令牌要用作session ID,那么一个好的数据结构是使其仍然非常快所需的一切),如果令牌是唯一的,则处理程序会在返回之前保存它。 这实在是太过分了。遵循将令牌设置为 UUID 和时间戳的组合的建议会更容易。如果除了 UUID 之外还使用 System.nanotime,我认为在任何时候都不会发生冲突。

© www.soinside.com 2019 - 2024. All rights reserved.