You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何生成最长7位、无需校验历史的唯一随机字母数字UID?

你当前的实现存在明确的唯一性风险:32位随机值仅有约42亿种可能,受生日悖论影响,生成量达到7.7万时碰撞概率就达到50%,生成量到100万时碰撞概率几乎为100%,完全无法满足硬性唯一要求。

方案1:基于自增ID混淆(100%无碰撞,优先推荐)

你当前表已经有自增主键,这是天然的全局唯一因子,对自增ID做可逆混淆后,即可得到无规律、随机感强、且绝对唯一的UID,完全不需要提前查询历史UID校验。

  • 核心逻辑:
    1. 字符集选择Base36(0-9、A-Z共36个字符),7位Base36最多可覆盖36^7 = 783亿个值,足够支撑绝大多数业务的规模需求,生成的UID格式和你给出的PNR样例完全一致。
    2. 用「固定盐异或+位置换」的方式混淆自增ID,彻底打乱ID的有序性,避免被遍历猜解:
      • 提前生成一个36位的随机固定盐,上线后不可修改
      • 将自增ID和盐做异或运算
      • 对运算结果的二进制位做固定顺序的置换,进一步打乱原有规律
    3. 将混淆后的数值转为Base36大写即可,不足7位无需补位也可正常使用。
  • 示例代码:
// 固定盐值,上线后禁止修改,可自定义为其他随机值
private static final long SALT = 0X2F7D9A4C1L;
// 36位二进制的置换顺序表,可自定义调整顺序
private static final int[] PERMUTE_TABLE = {3,1,4,0,2,6,5,9,7,10,8,12,15,11,13,14,17,19,16,22,18,20,24,21,23,26,28,25,31,27,29,33,30,32,35,34};

public static String generateUid(long autoIncrementId) {
    // 第一步:异或混淆
    long confusedId = autoIncrementId ^ SALT;
    // 第二步:位置换
    long permutedId = 0;
    for (int i = 0; i < 36; i++) {
        permutedId |= ((confusedId >> i) & 1) << PERMUTE_TABLE[i];
    }
    // 第三步:转Base36大写
    return Long.toString(permutedId, 36).toUpperCase();
}
  • 优势:生成效率极高,绝对不会出现碰撞,UID无连续规律无法被遍历,长度控制在6-7位符合要求。
方案2:低碰撞概率纯随机方案(适合生成UID时未拿到自增ID的场景)

如果生成UID时还未执行数据库插入操作,无法提前获取自增ID,可以通过提升随机位长度将碰撞概率降到可忽略的程度,同时配合数据库唯一索引兜底,不需要提前查库校验。

  • 核心逻辑:
    1. 改用Base36编码代替你当前用的Base32,相同长度下信息量更高。
    2. 生成36位的SecureRandom真随机值,刚好可以用7位Base36完整承载。
    3. 给数据库UID字段添加唯一索引,极端情况下出现碰撞时,数据库会抛出唯一约束异常,上层仅需做1-2次重试即可,不需要提前查询数据库。
  • 碰撞概率说明:36位随机值场景下,生成100万条UID的碰撞概率仅为0.0001%,生成1000万条的碰撞概率仅为1%,绝大多数业务场景下完全可以忽略风险。
  • 改进后的代码:
BigInteger big = new BigInteger(36, new SecureRandom());
return big.toString(36).toUpperCase();

内容的提问来源于stack exchange,提问作者Muhammad Umer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:39:04