12位纯数字兑换码的生成算法,如何尽可能保证不重复?

在只有PHP和mysql的环境下,做一个简单的发券、核销程序。其中券的兑换码必须为12位数字,数据量不会超过千万。如何生成不重复且乱序的券码?

最糟糕的方案是纯随机,然后到表里查一遍是否重复,重复则重新生成;不重复则插入

一个自认为好点的方案是用户id加一位随机数加截取时间戳后x位
例如用户ID为123,则是3位,加随机数4位。此时剩余8位则截取时间戳后8位补上。重复概率应该就很低了

在尽可能不遍历表的情况下,还有更难以重复的生成算法吗?求不吝赐教

阅读 14.4k
4 个回答

如果是按照用户ID和时间戳等生成md5摘要的方式的话,可以用base_convert将哈希后的md5值转为10进制,不过这样转出来的结果值长度肯定就不止12位了,还需要用字符串截取函数截取一下,但原本几十位的十进制数只截取12位那么唯一性就无法保证了,可能还不如直接截取ID加时间戳,看你的描述应该是在用户请求的时候才生成码,那么一个用户同一秒不能生成多张的情况下组合部分时间戳和用户ID还是没问题的。

考虑用户的ID和时间进行消息摘要算法,比如最简单内置的MD5或者SHA1,然后对于结果进行一定的压缩或者提取,转化成12位的

我感觉你的想法挺好啊,还可以还原进行验证兑换码的合法性。

消息摘要算法太混沌了,压缩到12位后效果和随机没有区别,多了还是会碰撞。

楼主的做法(id + 时间戳 + 随机数)基本能满足不碰撞的要求了,问题在于乱序。

可以仿效线性同余生成伪随机数的方法,找个大素数a和常数b,把id + 时间戳 + 随机数生成的数字输入函数f(x) = a * x + b (mod 1,000,000,000,000)里,只要a足够大(数量级跟1,000,000,000,000相近)就很随机了。而且由于a是素数,f是可逆的,这也保证了只要输入不重复,输出也不会重复。

另外建议拼接数字时把随机数放在高位,这样运算后输出的差别更大。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题