生成唯一字母 ID 求解 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lg106
V2EX    PHP

生成唯一字母 ID 求解

  •  
  •   lg106 2020-01-22 10:51:13 +08:00 11070 次点击
    这是一个创建于 2089 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个需求是不用数字作为用户 ID,要用英文字母

    我现在有三种解决方案

    第一种:用户注册时候,生成一个随机英文字符串,去查用户表,如果重复再重新生成,直到唯一。

    第二种:先生成一张字母 ID 表,每次用户从里面取,取了就标记为已用。

    第三种:用函数把用户数字 ID 转为字母 ID,但是转出来的 ID,两个相近的用户,字母 ID 太相似了。

    有什么更好的解决方案吗?

    53 条回复    2020-01-24 22:45:24 +08:00
    Varobjs
        1
    Varobjs  
       2020-01-22 10:57:12 +08:00 via Android
    就是随机生成不唯一的用户名呗
    lg106
        2
    lg106  
    OP
       2020-01-22 10:59:46 +08:00
    @Varobjs 也可以这么说,用户 ID 要显示在外面,我们不想让别人看到我们的数字 ID,所以想用英文来代替,包括我们的文章 ID 也是要弄成英文 ID
    imlinhanchao
        3
    imlinhanchao  
       2020-01-22 11:00:48 +08:00
    @lg106 uuid 可否?
    whypool
        4
    whypool  
       2020-01-22 11:01:07 +08:00
    新增数据可以用 UUID,把横杠去掉就行,就是有点长
    用户名+时间戳+MD5 也能生成唯一 ID
    crypto 库也能生成唯一 ID
    jfcherng
        5
    jfcherng  
       2020-01-22 11:01:56 +08:00 via Android
    hashids
    jinhan13789991
        6
    jinhan13789991  
       2020-01-22 11:03:25 +08:00 via Android
    第一个人是 AAAAAAAA,第二个人是 AAAAAAAB,以此类推~ 变相的 26 进制自增
    eojessie
        7
    eojessie  
       2020-01-22 11:04:46 +08:00
    @jinhan13789991 这个容易被枚举了。。。。
    lg106
        8
    lg106  
    OP
       2020-01-22 11:05:35 +08:00
    @imlinhanchao 可能太长了
    otakustay
        9
    otakustay  
       2020-01-22 11:05:55 +08:00
    就用自增键然后 hash 一下呢
    lg106
        10
    lg106  
    OP
       2020-01-22 11:06:25 +08:00
    @jinhan13789991 我第三种就是这种,可以用函数转化,但容易被找规律
    lg106
        11
    lg106  
    OP
       2020-01-22 11:06:45 +08:00
    @whypool 我试试第三种,UUID 有点长
    lg106
        12
    lg106  
    OP
       2020-01-22 11:06:58 +08:00
    @jfcherng 我试试去
    Varobjs
        13
    Varobjs  
       2020-01-22 11:08:21 +08:00 via Android
    @lg106 那就数字 id md5 下就可以了,多方便
    lg106
        14
    lg106  
    OP
       2020-01-22 11:10:25 +08:00
    @Varobjs 我忘了说了,长度只能是 8 到 10 位,太长了不行,类似这种 rczlihkgyt
    GM
        15
    GM  
       2020-01-22 11:10:45 +08:00   1
    HashID 了解一下,数据表可以继续用自增 id 字段,对外做个转换变成 HashID 就好了。
    009694
        16
    009694  
       2020-01-22 11:14:45 +08:00 via iPhone
    前两种方案有什么缺点吗?
    Marmot
        17
    Marmot  
       2020-01-22 11:17:01 +08:00   2
    hashids 靠谱
    cgpiao
        18
    cgpiao  
       2020-01-22 11:17:40 +08:00 via iPhone
    设备 id + 自定义格式时间 + 自增 转换为 36 进制
    lg106
        19
    lg106  
    OP
       2020-01-22 11:22:37 +08:00
    试了下 hashids,这个完美解决,感谢大佬们
    eason1874
        20
    eason1874  
       2020-01-22 11:25:52 +08:00
    怕 ID 暴露可以用 36 进制,36 个字符打乱顺序就不好猜了,但如果获得连续 ID 还是可以破解出来。
    vanishcode
        21
    vanishcode  
       2020-01-22 11:33:42 +08:00
    https://github.com/souyunku/SnowFlake
    不知道是不是楼主想要的。。
    xaplux
        22
    xaplux  
       2020-01-22 11:37:31 +08:00
    @vanishcode 很明显不是,楼主想要的是全字母的,17 楼说的 hashids 靠谱
    tabris17
        23
    tabris17  
       2020-01-22 11:50:06 +08:00
    snowflake 算法生成 64 位整数

    然后转换成 base53 字符串(仅包含字母和下划线)
    hubqin
        24
    hubqin  
       2020-01-22 11:52:24 +08:00
    取巧,Javascript:Math.random().toString(36).slice(2)
    wengcd
        25
    wengcd  
       2020-01-22 11:55:45 +08:00
    https://hashids.org

    配置密钥,真实根据密钥生成 hash 值;有密钥可反推出真实,没有则无法反推
    alaikis
        26
    alaikis  
       2020-01-22 11:58:50 +08:00
    数字 36 进制
    MrYELiex
        27
    MrYELiex  
       2020-01-22 13:00:43 +08:00
    snowflake
    Raymon111111
        28
    Raymon111111  
       2020-01-22 13:10:39 +08:00
    snowflake 这种方案然后把 0 到 9 映射到 a - j 上就行了.

    一个简单的实现是, 当前时间(unixtime, 秒和毫秒都可以) + 机器码(比如集群是 100 个机器, 那就号码就是 00 - 99) + 三位轮询的数(每个机器启动时候就拿到一个打乱的大小是 1000 的数组, 里面的数是 000 - 999, 生成的时候从里面取数然后移除, 空了再生成一次)

    这么干冲突的概率相当小(几乎不会有)
    looplj
        29
    looplj  
       2020-01-22 14:37:27 +08:00
    uuid->hash->baese64 取前 10 位
    sleepm
        30
    sleepm  
       2020-01-22 14:43:25 +08:00
    有个自增主键 id,然后,先插入新纪录,然后获取 id,再根据 id 生成全字母的 ID
    luopengfei14
        31
    luopengfei14  
       2020-01-22 14:44:56 +08:00 via iPhone
    36、62 进制都可以
    fx
        32
    fx  
       2020-01-22 15:33:21 +08:00
    hashids
    jeremaihloo
        33
    jeremaihloo  
       2020-01-22 16:14:54 +08:00
    nanoid

    github.com 上搜一下,不同语言都有实现,一定程度上满足需求吧
    qsbaq
        34
    qsbaq  
       2020-01-22 16:29:22 +08:00
    把 ID 弄个 md5 肯定唯一了
    songco
        35
    songco  
       2020-01-22 16:44:02 +08:00
    没有可读性要求可以直接 id 映射一下就行, 比如数字转换成 16 进制; 比如 0-9 映射成 10 个字幕

    有可读性要求的话, 准备字典, 然后随机生成两到组拼起来, 预先生成也行; 生成后查重复也行; 直接按顺序映射也可以, 生成的结果大概类似 docker 的默认名字, 比如 adoring_lovelace 之类的
    Liang
        36
    Liang  
       2020-01-22 16:45:08 +08:00
    @qsbaq md5 在一定概率下会重复的
    wzwwzw
        37
    wzwwzw  
       2020-01-22 18:50:25 +08:00
    uuid 去掉 - 呗。
    kkkkkrua
        38
    kkkkkrua  
       2020-01-22 19:18:38 +08:00 via iPhone
    将数字转成 58 进制
    hauzi
        39
    hauzi  
       2020-01-22 20:11:54 +08:00 via iPhone
    第一种
    fireapp
        40
    fireapp  
       2020-01-22 20:13:47 +08:00 via iPhone
    mongo object id 还不错可以试试
    lasuar
        41
    lasuar  
       2020-01-22 20:18:44 +08:00
    利用自增思想,A->B 等效于 1->2
    fdingiit
        42
    fdingiit  
       2020-01-22 20:22:46 +08:00
    有请求,再创建不是一个好的生产环境策略。

    我们的生产环境上,id 是有个预资源池,初始可能是 n 位,随用随取。如果用完了,就 stop the world 并再生成一个位数为 n+1 的 id 新池子。

    这个思路的来源是编译器中内存分配以及垃圾回收的几个简单算法。
    gamexg
        43
    gamexg  
       2020-01-22 21:02:00 +08:00
    hashid 挺好,
    我做过类似的另一个需求,
    不过原始 id 是二进制数据,直接固定 iv 的 aes 流加密来做的。
    rogwan
        44
    rogwan  
       2020-01-22 21:07:26 +08:00
    hashids + 盐。
    LancerEvo
        45
    LancerEvo  
       2020-01-22 21:28:07 +08:00
    记得在某个公司的代码里见过一个微服务 用的第二种实现
    zyqhi
        46
    zyqhi  
       2020-01-22 21:43:43 +08:00 via iPhone
    26 进制
    ech0x
        47
    ech0x  
       2020-01-22 21:53:22 +08:00
    生成一个 UUID 不就行了,UUID3 或者 UUID5
    wd
        48
    wd  
       2020-01-22 22:17:07 +08:00 via iPhone
    我觉得第一种就挺好的 uuid 里面取几位用 不会那么大概率需要生成第二次
    zpvip
        49
    zpvip  
       2020-01-22 22:42:41 +08:00 via Android
    我不知道为什么 Ruby on Rails 在国内这么不受待见。这个需求一行代码就搞定了

    gem 'friendly_id'
    lookas2001
        50
    lookas2001  
       2020-01-23 00:34:20 +08:00 via Android
    8 位 id 取 5 次都有重复的可能性基本上就为 0 了
    所以,第一种
    dandandanerdan
        51
    dandandanerdan  
       2020-01-23 06:57:56 +08:00
    uuid 是最安全的
    polymerdg
        52
    polymerdg  
       2020-01-23 09:05:53 +08:00
    我用的是 MD5(用名+戳+ 6 位)
    huzb
        53
    huzb  
       2020-01-24 22:45:24 +08:00
    用函数把用户 ID 转成字母 ID 是最好的,可以确保唯一且在前端就完成校验。相近 ID 这个可以用混淆和扩散的方式把变化打乱。我有总结过一篇文章:huzb.me/2018/03/23/简单的密码学生成唯一邀请码 /
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1577 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 16:28 PVG 00:28 LAX 09:28 JFK 12:28
    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