请教各位前辈关于高并发下生成订单唯一流水号的方法?附己见

发布于 2022-09-01 12:59:03 字数 433 浏览 13 评论 0

各位前辈们晚上好,之所以发这个帖子是因为之前在项目中用的生成随机流水号的工具类有问题,出现了重号,比如订单1的订单号是123,订单2的订单号也是123。

所使用的生成随机号码的规则为:类别(比如OD)+年月日时分秒+随机3位数字

可是我感觉随机这东西就是在碰运气啊,就算我加上毫秒,也有可能出现重号,毕竟3位数字太少,加多几位数字也一样,于事无补。

我能想到的解决方法如下:

1、UUID,可是32位太长了,用不上啊……

2、每次生成订单号后查一下数据库是否已经有该订单号,有的话则重新生成,这个感觉不靠谱,太慢了……

3、创建一个编号表,使用主键作为订单编号的一部分,因为主键自增是唯一的,可是用这个的话将来一旦量大了,那订单编号的位数就会越来越大,无法控制了

其他的方法没有想到更好的了,希望前辈们可以指导一下如何解决,谢谢前辈们了

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

゛时过境迁 2022-09-08 12:59:03

以下要素视情况组合

  • 日期
  • 秒数/毫秒数
  • 机器hash(不同机器不重复)
  • PID(不同进程不重复)
  • 用户ID
  • db自增(性能较差)
  • redis自增(性能不错,需要redis,有故障风险)
  • 类似mongodb的“单进程单秒内”的自增(性能最高)

另外,db/redis自增均可考虑跳步&缓存来降低压力(每次自增10/50/100回来后缓存在本地,本地的用完再去拿)

悟红尘 2022-09-08 12:59:03

各位前辈们好,我有一个想法不知道是否可行:

1、创建一个序列号表,只有一行数据,为序列号的值

2、生成序列号时,每次读取该表,从该表中读取该行数据,语句为:
SELECT SERIAL_NUM FROM SERIAL_TABLE WHERE ID = 1 FOR UPDATE;

3、每次读取的时候给该行使用FOR UPDATE上锁,读取完以后使用以下语句:
UPDATE SERIAL_TABLE SET SERIAL_NUM = SERIAL_NUM + 1 WHERE ID = 1;
COMMIT;

4、释放行锁,不知道这样是否可行,欸……

缱倦旧时光 2022-09-08 12:59:03

3方案有什么问题吗? 位数大了有什么后果吗? 并没有。
在3方案的基础上还可以预生成一些可用id..如果你真的需要这么大的并发的话。

二手情话 2022-09-08 12:59:03

这跟高并发关系不大, 而是你需要列队服务, 来避开刚并发的同时执行而已.

自增是最好的办法了, 位数增大不很正常吗,说明你订单多啊. 当订单超过一定数量分表啊.

带刺的爱情 2022-09-08 12:59:03

光时间戳还不够吗,YYYYMMddHHmmssSSS+uid试试

宫墨修音 2022-09-08 12:59:03

http://www.zuidaima.com/share/1550463224040448.htm
不知道这个可以不?高并发下,我觉得尽量少点去访问db吧

皇甫轩 2022-09-08 12:59:03

要想省事就用Hazelcast里的distributed counter,用法类似于AtomicLong

迟到的我 2022-09-08 12:59:03
md5($uid.'_'.uniqid().'_'.rand(0,99999).'_'.$productName);

$productName为用户购买商品的名称,这个订单号都还重复的话,别搞电商了,买彩票吧,来钱快

过潦 2022-09-08 12:59:03

这个位数的影响可以忽略吧,你用任何的计数方式,都会增长,又不存在你换种计数就会少了几位数。除非你用16进位制或者更高的进位制才有可能。

同时申请id的方法就是把并发的请求改成串行,其实用redis设置一个自增值,每次取就加一,这个就非常合适。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文