java - 如何在 Java 中生成唯一的 Long
问题描述
我正在尝试生成唯一的数字 ID,以用作 Mysql 数据库中的主键。由于系统的分布式特性,我需要在数据库之外生成它们。
这是我的尝试:
@RunWith(MockitoJUnitRunner.class)
public class AbstractEntityTest {
@Test
public void testGenerateUniqueId() {
val ids = new HashSet<Long>();
val duplicates = new HashSet<Long>();
for (int i = 0; i < 1000000; i++) {
val id = System.currentTimeMillis() +
(ThreadLocalRandom.current().nextLong(9999999) + ThreadLocalRandom.current().nextLong(9999999));
if (!ids.add(id)) {
duplicates.add(id);
}
}
System.out.println("ids: " + ids.size());
System.out.println("Duplicates: " + duplicates.size());
assertThat(duplicates).isEmpty();
}
}
结果是:
ids: 967265
Duplicates: 31939
任何人都可以提出一种更好的方法来生成真正独特long
的 Java 吗?
一个解决方案似乎是:
@Test
public void testGenerateUniqueId_withUUID() {
val ids = new HashSet<Long>();
val duplicates = new HashSet<Long>();
for (int i = 0; i < 1000000; i++) {
val id = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE;
if (!ids.add(id)) {
duplicates.add(id);
}
}
System.out.println("ids: " + ids.size());
System.out.println("Duplicates: " + duplicates.size());
assertThat(duplicates).isEmpty();
}
结果是:
ids: 1000000
Duplicates: 0
这是 3000 万代的 5 次迭代:
@Test
public void testGenerateUniqueId_withUUID() {
val iterations = 5;
for (int j = 0; j < iterations; j++) {
val ids = new HashSet<Long>();
val duplicates = new HashSet<Long>();
for (int i = 0; i < 30000000; i++) {
val id = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE;
if (!ids.add(id)) {
duplicates.add(id);
}
}
System.out.println(String.format("Iteration %s of %s", j + 1, iterations));
System.out.println("ids: " + ids.size());
System.out.println("Duplicates: " + duplicates.size());
assertThat(duplicates).isEmpty();
}
}
结果是:
Iteration 1 of 5
ids: 30000000
Duplicates: 0
Iteration 2 of 5
ids: 30000000
Duplicates: 0
Iteration 3 of 5
ids: 30000000
Duplicates: 0
Iteration 4 of 5
ids: 30000000
Duplicates: 0
Iteration 5 of 5
ids: 30000000
Duplicates: 0
我添加了以毫秒为单位的当前时间,以帮助处理运行过程之外的唯一性。
@Test
public void testGenerateUniqueId_withUUID_andCurrentTimeMilliseconds() {
val iterations = 5;
val duplicates = new HashSet<Long>();
for (int j = 0; j < iterations; j++) {
val ids = new HashSet<Long>();
for (int i = 0; i < 30000000; i++) {
val id = System.currentTimeMillis() + UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE;
if (!ids.add(id)) {
duplicates.add(id);
}
}
System.out.println(String.format("Iteration %s of %s", j + 1, iterations));
System.out.println("ids: " + ids.size());
System.out.println("Duplicates: " + duplicates.size());
assertThat(duplicates).isEmpty();
}
}
解决方案
如果可能,我建议您切换到UUID,我认为它更适合您的目的。使用 UUID,您可以:
UUID uuid = UUID.randomUUID();
推荐阅读
- css - 如何在 Alfresco 中更改 aikau-1.0.101.10.jar 中的 CSS 文件
- laravel - 如何从复选框选中的laravel设置值变量?
- scala - 在 scala 中写入 JDBC 源
- jquery - 如何在输入时触发输入文本中的事件?
- ios - swift:在执行另一个动作后调用动作
- asp.net-core - 即使 env.IsDevelopment 为真,Asp.Net Core 也不显示开发人员异常页面
- elasticsearch - Elasticsearch - 文本类型正则表达式
- python - Line Magics - PyCharm 中未解决的引用
- jquery - 异步加载内容不会减慢网站加载时间
- gstreamer - 构建 Gstreamer 编辑服务失败