最近有个需求,按批次生成一定数量的18位唯一随机字符串(数字,大小写字母组成)。
因为考虑到效率,不可能生成一个去表里遍历是否存在,所以我每个批次生成6位批次号,再用rand生成12位随机字符串放在批次号后面组成18位字符串,当然这样虽然大大减少了重复的可能性,还是不能保证完全重复,存储过程还是需要事务去保证以防主键重复。不知道各位有没有什么更优的方法解决此类问题?

解决方案 »

  1.   

    直接用uuid啊
    mysql> select replace(uuid(),'-','');
    +----------------------------------+
    | replace(uuid(),'-','')           |
    +----------------------------------+
    | 674a5c443cf211e1a2440019b9e04a91 |
    +----------------------------------+
    1 row in set (0.00 sec)
      

  2.   

    要求是18位,你用uuid的话,截字符串的话就不能保证唯一了。
      

  3.   

    "所以我每个批次生成6位批次号,再用rand生成12位随机字符串放在批次号后面组成18位字符串,当然这样虽然大大减少了重复的可能性,"你这种 批次号 + 12位随机串 的方式只是易于管理查验,并不能“大大减少了重复的可能性”,相反,是“大大提高了重复的可能性”,因为你会有相当多的数据前6位是相同的。有个思路,你先只管生成18位随机字符串,然后找个加密算法过一遍,取生成的密文为正式字符串。因为象RSA、MD5这类的现代加密算法都有个特点:同样的明文进去,出来的密文仍然不同。所以,就算你进去的字符串是一样的,出来的密文也肯定不一样。
      

  4.   

    关于重复的可能性,你可能还没理解我的意思,比如我一个批次生成1000个随机串,我先生成一个批次号,可以在批次表里检查唯一性,这样我只要保证后面12位在1000个中的唯一性,而不需要保证在全表中的唯一性了。所以是大大减少了重复的可能性。至于你说的加密算法,如果你不能解决随机字符串的唯一性问题的话,后面再加密也是徒劳的。我们主要需要解决唯一性问题。当然如果我们先用唯一时间戳再MD5加密的话,和UUID是一个问题,MD5生成出来是16位和32位。
      

  5.   

    如果只是18位,取uuid的第9到26位,并加上是否重复键判断,总体效果也还算不错。重复的机率比较小。
      

  6.   

    如果只考虑唯一及均匀分布的话,不考虑效率的话,
    CONCAT(
             LEFT(CONV(CRC32(RAND()), 16, 36), 6), -- 前6位为rand的crc32的前6位,以36进制表示(0-9,A=10,Z=36)
             LEFT(CONV(CRC32(UUID()), 16, 36), 6), -- 中间6位,用UUID
             LEFT(CONV(CRC32(SIN(RAND())), 16, 36), 6) -- 最后6位,用sin(rand())
    )
    或者其他类似的方法,注意CONV只能处理32bit,所以必须分段处理。
      

  7.   


    第一个问题,如果你对这1000个随机串的后12位都做唯一性检查,当然能保证唯一,但是会损失时间。而我的默认前提是只管生成,不管校验。所以在此前提下,你的这个批次号 + 随机串 会提高重复性。第二个问题,我想你对RSA加密算法还不太了解。它所达到的效果就是和:“如果你不能解决随机字符串的唯一性问题的话,后面再加密也是徒劳的。”这句话是相反的。我在前面说过,哪怕是相同的一个随机串,进去加密后,出来的密文也是绝对不一样的。
      

  8.   

    第一个问题,的确是你没理解我的意思,1000个随机串我只对流水号做一个一次检查,后12位并没做检查。第二个问题,是我理解错了,我以为是用mysql的md5函数,因为当初发起这个讨论只是找数据库层面的解决方案。