84669 person learning
152542 person learning
20005 person learning
5487 person learning
7821 person learning
359900 person learning
3350 person learning
180660 person learning
48569 person learning
18603 person learning
40936 person learning
1549 person learning
1183 person learning
32909 person learning
在只有PHP和mysql的环境下,做一个简单的发券、核销程序。其中券的兑换码必须为12位数字,数据量不会超过千万。如何生成不重复且乱序的券码?
最糟糕的方案是纯随机,然后到表里查一遍是否重复,重复则重新生成;不重复则插入
一个自认为好点的方案是用户id加一位随机数加截取时间戳后x位例如用户ID为123,则是3位,加随机数4位。此时剩余8位则截取时间戳后8位补上。重复概率应该就很低了
在尽可能不遍历表的情况下,还有更难以重复的生成算法吗?求不吝赐教
业精于勤,荒于嬉;行成于思,毁于随。
考虑用户的ID和时间进行消息摘要算法,比如最简单内置的MD5或者SHA1,然后对于结果进行一定的压缩或者提取,转化成12位的
如果是按照用户ID和时间戳等生成md5摘要的方式的话,可以用base_convert将哈希后的md5值转为10进制,不过这样转出来的结果值长度肯定就不止12位了,还需要用字符串截取函数截取一下,但原本几十位的十进制数只截取12位那么唯一性就无法保证了,可能还不如直接截取ID加时间戳,看你的描述应该是在用户请求的时候才生成码,那么一个用户同一秒不能生成多张的情况下组合部分时间戳和用户ID还是没问题的。
我感觉你的想法挺好啊,还可以还原进行验证兑换码的合法性。
消息摘要算法太混沌了,压缩到12位后效果和随机没有区别,多了还是会碰撞。
楼主的做法(id + 时间戳 + 随机数)基本能满足不碰撞的要求了,问题在于乱序。
可以仿效线性同余生成伪随机数的方法,找个大素数a和常数b,把id + 时间戳 + 随机数生成的数字输入函数f(x) = a * x + b (mod 1,000,000,000,000)里,只要a足够大(数量级跟1,000,000,000,000相近)就很随机了。而且由于a是素数,f是可逆的,这也保证了只要输入不重复,输出也不会重复。
f(x) = a * x + b (mod 1,000,000,000,000)
另外建议拼接数字时把随机数放在高位,这样运算后输出的差别更大。
我的卡券类号码都是一位特定大写随机英文字典中抽一位+uid+time()+rand(十位数),然后截取16位出来生成比如T132-0161-2052-3091,有些超市用户一个月就分发百万张出去,没有重复的反馈.之所以加英文,主要还是增加接口查询被随机碰撞破解的难度.
考虑用户的ID和时间进行消息摘要算法,比如最简单内置的MD5或者SHA1,然后对于结果进行一定的压缩或者提取,转化成12位的
如果是按照用户ID和时间戳等生成md5摘要的方式的话,可以用base_convert将哈希后的md5值转为10进制,不过这样转出来的结果值长度肯定就不止12位了,还需要用字符串截取函数截取一下,但原本几十位的十进制数只截取12位那么唯一性就无法保证了,可能还不如直接截取ID加时间戳,看你的描述应该是在用户请求的时候才生成码,那么一个用户同一秒不能生成多张的情况下组合部分时间戳和用户ID还是没问题的。
我感觉你的想法挺好啊,还可以还原进行验证兑换码的合法性。
消息摘要算法太混沌了,压缩到12位后效果和随机没有区别,多了还是会碰撞。
楼主的做法(id + 时间戳 + 随机数)基本能满足不碰撞的要求了,问题在于乱序。
可以仿效线性同余生成伪随机数的方法,找个大素数a和常数b,把id + 时间戳 + 随机数生成的数字输入函数
f(x) = a * x + b (mod 1,000,000,000,000)
里,只要a足够大(数量级跟1,000,000,000,000相近)就很随机了。而且由于a是素数,f是可逆的,这也保证了只要输入不重复,输出也不会重复。另外建议拼接数字时把随机数放在高位,这样运算后输出的差别更大。
我的卡券类号码都是一位特定大写随机英文字典中抽一位+uid+time()+rand(十位数),然后截取16位出来生成比如T132-0161-2052-3091,有些超市用户一个月就分发百万张出去,没有重复的反馈.
之所以加英文,主要还是增加接口查询被随机碰撞破解的难度.