我遇到过一些代码,它们通过UUID.randomUUID()生成许多UUID,取每个UUID的最后7位(最新版本的UUID按照熵均匀分布),并将其用作向数据库中插入行的键.

我想知道相撞的可能性有多大.我记得有the Birthday Problem个.这就是那个问题的一个例子,不是吗?一年中不是365天,而是16^7个可能的字符串.然后根据维基百科的页面,给定n个字符串,冲突的概率为

enter image description here

其中d是16^7.

一位同事声称,他们能够插入50,000行,没有任何问题.我对此表示怀疑,因为与n=50,000d=16^7相撞的可能性是

1-((16^7-1)/16^7)^(50000*(50000-1)/2) = 99.05%

但后来我查了我们的数据库.事实上,5万个插入物成功了.

这怎么可能?(除此之外,他们真的很幸运.)我是不是错用了生日问题?


Edit

这是一个最低限度的测试,显示有should起碰撞事件.

import java.util.UUID;
import java.util.HashSet;

public class MyClass {
    public static void main(String args[]) {
        final int N = 50000;
        for (int trial = 0; trial < 10; trial++) {
            HashSet<String> strings = new HashSet<>();
            Boolean success = true;
            for (int i = 0; i < N; i++) {
                String uuid = UUID.randomUUID().toString();
                String id = uuid.substring(uuid.length() - 7);
                if (strings.contains(id)) {
                    success = false;
                    // System.out.println(id);
                    break;
                }
                strings.add(id);
            }
            System.out.println(success);
        }
    }
}

当N=50,000时,10次try 中有10次发生冲突-预计碰撞率为99%.对于N=10,000,我看到10次try 中有0次、1次、2次或3次发生冲突,这都在17%的冲突率的预期范围内.

推荐答案

最后,我有了一个解释.谢谢大家,是你们贡献了各种可能性,驱使我继续调查.

tl;dr-我以为在插入时有had个唯一的约束,因为数据库中确实有50,000个不同的代码.但事实证明,当时有not个限制因素.在最初的50,000个副本中确实存在副本,一个月后通过一次性的SQL语句(通过附加"1"进行修改)发现并修改了这些副本.

Full explanation:

此代码是关于生成一次性使用促销代码,如SUMMER23-65ACFF9.这就是我如何推断数据库中确实插入了50,000,distinct个代码:

enter image description here

该表没有时间戳字段(e.g. LAST_MODIFIED),或者我可能更早地得到了提示.我只知道50000个促销代码中的batch个是在2023年1月6日插入的,也就是3个月前.

enter image description here

我在2023年1月6日之前的最后一次提交时浏览了回购,看看当时的代码是否有什么东西可能允许50,000个代码成功.相关代码如下:

enter image description here

我相信,由于对.Rollback()的调用,50,000行的插入是自动完成的.换句话说,如果单个插入失败,则在此之前的所有插入都应该回滚.

(因此,一种可能性是,我的同事只是不停地反复try ,直到他们中了1%的头奖.但当我问他们时,情况似乎并非如此.他们根本不记得必须重试.)

我确实想知道在插入时是否存在唯一PROMO_CODE_ID的约束.我确认它确实存在:

enter image description here

我希望找到创建此约束的时间戳,但没有立即看到.我本应该更进一步,但我没有这样做,因为:我已经查询了distinct个PROMO_CODE_ID,得到了50,000个(见上面的第一个屏幕截图).无论有无约束,最终得到50,000个不同代码的概率仍然不到1%.This is where I made a faulty assumption: that the codes hadn't been tampered with since.

今天,我发现Liquibase在2月份(成功插入50,000次之后的一个月)对Liquibase XML进行了更改,显然添加了以下限制:

enter image description here

但请注意,除了添加唯一约束外,更改还带来了SQL.We essentially ran a script to add a "1" to the end of all duplicate codes.所以that是"插入50,000个没有重复的代码"是如何成功的:它没有--它一开始是没有约束的,后来被纠正了.

Java相关问答推荐

无法运行Java(已解决)

找到允许的最大底片

JUnit—如何模拟局部变量对象方法调用

Java inline Double条件和值解装箱崩溃

给定Java枚举类,通过值查找枚举

如何以干净的方式访问深度嵌套的对象S属性?

Hibernate 6支持Joda DateTime吗?

当返回Mono<;Something>;时,不会调用Mono<;void>;.flatMap

具有阻塞方法的开源库是否应该为执行提供异步选项?

如何让JVM在SIGSEGV崩溃后快速退出?

Jenv-相同的Java版本,但带有前缀

S,要对Java复制构造函数深度克隆所有属性进行单元测试,最可靠的方法是什么?

Oj算法 MatrixR032从字符串、归一化和余弦相似度计算创建

如何制作回文程序?

在具有Quarkus Panache的PostgreSQL中将JSON数据存储为JSONB时,会将其存储为转义字符串

我们可以在方法中声明接口吗?

为什么Instant没有从UTC转换为PostgreSQL的时区?

ResponseEntity.控制器截断响应的JSON部分

使用StringBuilder和append方法创建字符串时Java字符串内部方法的问题

Maven创建带有特定类的Spring Boot jar和普通jar