公眾號推文發現一個介紹小米生成訂單號生成規則,原文:https://mp.weixin.qq.com/s/YQO_PA-kumg5ZOgjDugtIQ
剩下的主要工作就是我們如何去設計一個訂單號規則!
在設計規則之前,我們先來看看互聯網幾個大廠的訂單號格式。
京東商城訂單號格式:157444499
蘇寧易購訂單號格式:2000839647
凡客誠品訂單號格式:213052230059
銀泰網訂單號格式:10030522161715
小米訂單號格式:1111218032345170
我們先來分析一下凡客誠品和銀泰網的訂單號生成規則。
凡客誠品和銀泰網訂單號都含有 0522,這是因為這 2 張訂單都是2013年5月22號下的訂單。
基本猜測一下,凡客的訂單規則是:業務編碼+年的后2位+月+日+訂單數;泰網的訂單號規則:年的第三位數+業務編碼+年的后1位+月+日+訂單數;而京東商城和蘇寧易購的訂單號看不出規則。
最后我們來分析一下小米訂單號1111218032345170,可以將其分解成四個部分1——111218—03234—5170。
- 第一部分,1 表示購買,2 表示退貨。
- 第二部分,表示 2011 年 12 月 18 日下的單,前面兩位省掉了。
- 第三部分,時間戳對應
00:53:54,換算成秒是03234秒。 - 最后一部分,表示在同一秒內下的第 5170 單,也就是說,小米認為,在一秒內不會超過一萬個訂單。
總結起來,小米的訂單規則是:業務編碼+年的后 2 位+月+日+秒+訂單數,固定長度為16,這種訂單號規則可以保證 100 年不會重復!
===================分割線======================
然后我去小米下了個訂單,發現中間的時分秒規則,和推文介紹並不一致,不過,這種思路對於大多數應用(並發量沒那么高)來說,足夠了
下面實現一把(第一位業務編碼不要了):
依賴工具:redis、hutool工具類,StringUtils
package com.doc.test; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import com.xdf.ucan.CloudDocWebApplication; import org.apache.commons.lang3.StringUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.test.context.junit4.SpringRunner; import java.time.LocalDateTime; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * @author lihaoyang * @date 2022/2/4 */ @RunWith(value = SpringRunner.class) @SpringBootTest(classes = CloudDocWebApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class TestOrderNo { @Autowired StringRedisTemplate stringRedisTemplate; /** * 小米訂單號1-11-12-18-03234-5170 * 第一部分,1 表示購買,2 表示退貨。 * 第二部分,表示 2011 年 12 月 18 日下的單,前面兩位省掉了。 * 第三部分,時間戳對應00:53:54,換算成秒是03234秒。 * 最后一部分,表示在同一秒內下的第 5170 單,也就是說,小米認為,在一秒內不會超過一萬個訂單。 * <p> * 小米的訂單規則是:業務編碼+年的后 2 位+月+日+秒+訂單數,固定長度為16,這種訂單號規則可以保證 100 年不會重復! * * 220205706030202 * 220205706030203 * 220205706030204 * 220205706030207 * 220205706030206 * 220205706030205 * 220205706030209 * 220205706030208 * 220205706030210 * * 111218032345170 */ @Test public void tttt() throws Exception{ ExecutorService executorService = Executors.newFixedThreadPool(10); for(int i=0;i<1000;i++){ executorService.execute(()->{ System.out.println(genOrderNo()); }); } Thread.sleep(10000); } private String genOrderNo(){ //獲取當前時間 LocalDateTime now = LocalDateTime.now(); String YYMMDD = StringUtils.substring(DateUtil.format(now, DatePattern.PURE_DATE_PATTERN),2); String seconds = now.getHour()*3600+now.getMinute()*60+now.getSecond()+""; String secondsFMT = StringUtils.leftPad(seconds, 5, "0"); String orderNoPrefix = YYMMDD+secondsFMT; String redisKeyPrefix = "order_no:"+orderNoPrefix; Long increment = stringRedisTemplate.boundValueOps(redisKeyPrefix).increment(); if(increment == 1){ //每一秒的第一個訂單號,設置一下key過期時間 stringRedisTemplate.boundValueOps(redisKeyPrefix).expire(60, TimeUnit.SECONDS); } return orderNoPrefix+StringUtils.leftPad(String.valueOf(increment),4,"0"); } }
生成一批訂單號看看:
220205762470003
220205762470007
220205762470008
220205762470005
220205762470006
220205762470002
220205762470004
220205762470010
220205762470009
220205762470001
220205762470012
220205762470011
220205762470015
220205762470016
220205762470013
220205762470014
220205762470019
220205762470018
220205762470017
220205762470020
220205762470021
220205762470027
220205762470025
220205762470023
220205762470024
220205762470026
220205762470028
220205762470029
220205762470022
220205762470032
220205762470037
220205762470038
220205762470039
220205762470030
220205762470031
220205762470033
220205762470035
第一秒生成了410個訂單號,第二秒生成了590個,正好1000個。

