国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

血的教訓(xùn) ,一次訂單號(hào)重復(fù)的事故我差點(diǎn)被開(kāi)除

開(kāi)發(fā) 前端
系統(tǒng)出現(xiàn)了兩個(gè)一模一樣的訂單號(hào),訂單的內(nèi)容卻不是一樣的,而且事情發(fā)生的不止一次,被老板發(fā)現(xiàn)之后,當(dāng)月績(jī)效被扣光!

[[442441]]

本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲Tang。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。

一、介紹

曾經(jīng)有個(gè)項(xiàng)目,我們線上出了一次事故,這個(gè)事故的表象大體是這樣的:

系統(tǒng)出現(xiàn)了兩個(gè)一模一樣的訂單號(hào),訂單的內(nèi)容卻不是一樣的,而且事情發(fā)生的不止一次,被老板發(fā)現(xiàn)之后,當(dāng)月績(jī)效被扣光!

事后經(jīng)過(guò)排查,產(chǎn)生這個(gè)問(wèn)題,總結(jié)主要有兩個(gè)原因:

  • 數(shù)據(jù)庫(kù)訂單表里面,對(duì)訂單編號(hào)沒(méi)有設(shè)置唯一鍵約束
  • 生成訂單編號(hào)的時(shí)候,采用了隨機(jī)數(shù),導(dǎo)致有部分單號(hào)發(fā)生了重復(fù)

針對(duì)這個(gè)問(wèn)題也做了一些研究,有一些收獲想分享給大家!

本文主要以討論電商的訂單編碼規(guī)則為案例,其他類型的服務(wù)編號(hào)設(shè)計(jì)思路其實(shí)也是相似的。

不廢話,直接干貨!

訂單命名的幾種規(guī)則總結(jié):

  • 不重復(fù):這點(diǎn)我相信大家都懂,必須全局唯一
  • 安全性:訂單號(hào)需要做到不容易被人為的猜測(cè)或者推測(cè)出來(lái),例如訂單號(hào)就是流水號(hào)的話,那么別人就很容易從訂單號(hào)推測(cè)出公司的整體運(yùn)營(yíng)情況。
  • 禁用隨機(jī)碼:很多人分析生成訂單號(hào)的時(shí)候,第一個(gè)念頭肯定是不重復(fù)唯一性,那么第二個(gè)念頭可能就是安全性,想要同時(shí)滿足前兩者,很容易想到使用隨機(jī)碼,隨機(jī)碼從一定程度來(lái)說(shuō),更安全、不重復(fù)性更高,但是可讀性差,有概率會(huì)發(fā)生重復(fù)。
  • 防止并發(fā):針對(duì)系統(tǒng)的并發(fā)業(yè)務(wù)場(chǎng)景(如秒殺),需要做到并發(fā)場(chǎng)景下,訂單編號(hào)生成快速、不重復(fù)等要求
  • 控制位數(shù):訂單號(hào)的位數(shù)盡量在 10 位 ~ 18 位之間。太短的情況下,如果交易量過(guò)大,很難做到防止重復(fù),太長(zhǎng)可讀性差、意義也不大。

二、方案實(shí)踐

上面提到了訂單編號(hào)生成的規(guī)則,那要實(shí)現(xiàn)這樣的規(guī)則,該如何實(shí)現(xiàn)會(huì)比較好呢?

下面總結(jié)幾種常見(jiàn)的處理方式,我們一一分析!

2.1、方案一:UUID

UUID 是Universally Unique Indentifier的縮寫,翻譯為通用唯一識(shí)別碼,顧名思義 UUID 是一個(gè)用于記錄唯一標(biāo)識(shí)一條的數(shù)據(jù),其按照開(kāi)放軟件基金會(huì)(OSF)指定的標(biāo)準(zhǔn)進(jìn)行計(jì)算,用到了以太網(wǎng)卡地址(MAC)、納秒級(jí)時(shí)間、芯片 ID 碼和許多可能的數(shù)字。

總的來(lái)說(shuō),UUID 碼由以下三部分組成:

  • 當(dāng)前日期和時(shí)間
  • 時(shí)鐘序列
  • 全局唯一的 IEEE 機(jī)器識(shí)別碼(如果有網(wǎng)卡從網(wǎng)卡獲得,沒(méi)有網(wǎng)卡則通過(guò)其他方式獲得)

UUID 的標(biāo)準(zhǔn)形式包含 32 個(gè) 16 進(jìn)制數(shù)字,以連字號(hào)分為五段,示例:00000191-adc6-4314-8799-5c3d737aa7de。

以java為例,通過(guò)以下方式即可生成:

  1. String uuid = UUID.randomUUID().toString(); 

這種方案,雖然實(shí)現(xiàn)簡(jiǎn)單、方便;但是數(shù)據(jù)庫(kù)查詢效率非常差,而且內(nèi)容長(zhǎng),在實(shí)際的項(xiàng)目場(chǎng)景開(kāi)發(fā)中,一般用于于記錄用戶的手機(jī)設(shè)備ID等硬件信息!

因此不推薦采用 uuid 來(lái)生成訂單編號(hào)!

2.2、方案二:數(shù)據(jù)庫(kù)自增

所謂數(shù)據(jù)庫(kù)自增,意思是在數(shù)據(jù)庫(kù)中給某個(gè)列設(shè)置為自增列,并且給該列設(shè)置一個(gè)初始值,代碼層面無(wú)需任何特殊處理,以 Mysql 的用戶表 ID 列為例,可以通過(guò)如下方式在創(chuàng)建表的時(shí)候生產(chǎn)。

  1. CREATE TABLE `tb_user` ( 
  2.   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
  3.   `namevarchar(20) DEFAULT NULL
  4.   PRIMARY KEY (`id`) 
  5. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 

這種通過(guò)數(shù)據(jù)庫(kù)自增方式實(shí)現(xiàn)唯一值,在單體服務(wù)下是沒(méi)有問(wèn)題,但是在大流量分布式服務(wù)環(huán)境下,并發(fā)性能很低。

以后數(shù)量大的時(shí)候,需要對(duì) mysql 進(jìn)行分庫(kù)分表,此時(shí)訂單號(hào)會(huì)重復(fù),因此不推薦采用!

2.3、方案三:雪花算法

Snowflake(中文簡(jiǎn)稱:雪花算法) 是 Twitter 內(nèi)部的一個(gè) ID 生算法,可以通過(guò)一些簡(jiǎn)單的規(guī)則保證在大規(guī)模分布式情況下生成唯一的 ID 號(hào)碼。其內(nèi)部結(jié)構(gòu)如下:

可以很清晰的看出,Snowflake 由 4個(gè)部分組成:

  • 第一部分:bit 值,為未使用的符號(hào)位
  • 第二部分:由 41 位的時(shí)間戳(毫秒)構(gòu)成,它的取值是當(dāng)前時(shí)間相對(duì)于某一時(shí)間的偏移
  • 第三部分:表示工作機(jī)器 id,由服務(wù)節(jié)點(diǎn) id 和數(shù)據(jù)中心 id 組合而成
  • 第四部分:表示每個(gè)工作機(jī)器每毫秒生成的序列號(hào) ID,同一毫秒內(nèi)最多可生成生產(chǎn) 4095 個(gè) ID。

由于在 Java 中 64bit 的整數(shù)是 long 類型,因此在 Java 中 SnowFlake 算法生成的 id 就是 long 來(lái)存儲(chǔ)的。

SnowFlake 算法可以保證:

  • 所有生成的 id 按時(shí)間趨勢(shì)遞增
  • 整個(gè)分布式系統(tǒng)內(nèi)不會(huì)產(chǎn)生重復(fù)id(因?yàn)橛蟹?wù)節(jié)點(diǎn) id 和數(shù)據(jù)中心 id 來(lái)做區(qū)分)

需要注意的是:

  • 在分布式環(huán)境中,5 個(gè) bit 位的 datacenter 和 worker 表示最多能部署 31 個(gè)數(shù)據(jù)中心,每個(gè)數(shù)據(jù)中心最多可部署 31 臺(tái)節(jié)點(diǎn)。
  • 41 位的二進(jìn)制長(zhǎng)度最多能表示2^41 -1毫秒即 69 年,所以雪花算法最多能正常使用 69 年,為了能最大限度的使用該算法,在使用的時(shí)候,應(yīng)該為其指定一個(gè)開(kāi)始時(shí)間,不然會(huì)發(fā)生重復(fù)!

在高并發(fā)的環(huán)境下,Snowflake 算法可以生成全局唯一的訂單編號(hào),但是他的長(zhǎng)度達(dá)到21位,因此不推薦采用,但是可以用它來(lái)生成主鍵 ID,是完全沒(méi)有問(wèn)題的!

2.4、方案三:分布式組件

要想在分布式環(huán)境下生成一個(gè)唯一的訂單編號(hào),我們可以通過(guò)分布式組件的方式,來(lái)幫忙我們生成全局唯一的訂單號(hào),例如我們可以采用 redis 分布式緩存組件中的incr命令,來(lái)幫我們生成一個(gè)全局自增長(zhǎng)的序列號(hào)!

實(shí)現(xiàn)邏輯如下:

  1. //基于某個(gè)key實(shí)現(xiàn)自增長(zhǎng) 
  2. String res = jedis.get(key); 
  3. if (StringUtils.isBlank(res)) { 
  4.     jedisClient.set(key, INIT_ID);//設(shè)置自增長(zhǎng)的初始值,INIT_ID 是初始值 
  5.     jedisClient.expire(key, seconds);//設(shè)置過(guò)期時(shí)間,seconds 是多少秒過(guò)期 
  6. long orderId = jedis.incr(key);//存在就生成+1的訂單號(hào) 

這種方式生成的自增長(zhǎng)序列號(hào),非常的快,可以很好的滿足大流量環(huán)境下的編號(hào)要求唯一的特性!

剩下的主要工作就是我們?nèi)绾稳ピO(shè)計(jì)一個(gè)訂單號(hào)規(guī)則!

在設(shè)計(jì)規(guī)則之前,我們先來(lái)看看互聯(lián)網(wǎng)幾個(gè)大廠的訂單號(hào)格式。

京東商城訂單號(hào)格式:157444499

蘇寧易購(gòu)訂單號(hào)格式:2000839647

凡客誠(chéng)品訂單號(hào)格式:213052230059

銀泰網(wǎng)訂單號(hào)格式:10030522161715

小米訂單號(hào)格式:1111218032345170

我們先來(lái)分析一下凡客誠(chéng)品和銀泰網(wǎng)的訂單號(hào)生成規(guī)則。

凡客誠(chéng)品和銀泰網(wǎng)訂單號(hào)都含有 0522,這是因?yàn)檫@ 2 張訂單都是2013年5月22號(hào)下的訂單。

基本猜測(cè)一下,凡客的訂單規(guī)則是:業(yè)務(wù)編碼+年的后2位+月+日+訂單數(shù);泰網(wǎng)的訂單號(hào)規(guī)則:年的第三位數(shù)+業(yè)務(wù)編碼+年的后1位+月+日+訂單數(shù);而京東商城和蘇寧易購(gòu)的訂單號(hào)看不出規(guī)則。

最后我們來(lái)分析一下小米訂單號(hào)1111218032345170,可以將其分解成四個(gè)部分1——111218—03234—5170。

  • 第一部分,1 表示購(gòu)買,2 表示退貨。
  • 第二部分,表示 2011 年 12 月 18 日下的單,前面兩位省掉了。
  • 第三部分,時(shí)間戳對(duì)應(yīng)00:53:54,換算成秒是03234秒。
  • 最后一部分,表示在同一秒內(nèi)下的第 5170 單,也就是說(shuō),小米認(rèn)為,在一秒內(nèi)不會(huì)超過(guò)一萬(wàn)個(gè)訂單。

總結(jié)起來(lái),小米的訂單規(guī)則是:業(yè)務(wù)編碼+年的后 2 位+月+日+秒+訂單數(shù),固定長(zhǎng)度為16,這種訂單號(hào)規(guī)則可以保證 100 年不會(huì)重復(fù)!

同樣的,借鑒小米的訂單號(hào)規(guī)則,我們也可以生成同樣的訂單號(hào),實(shí)現(xiàn)過(guò)程如下:

  1. //獲取當(dāng)前時(shí)間 
  2. Date currentTime  = new Date(); 
  3. //格式化當(dāng)前時(shí)間為【年的后2位+月+日】 
  4. String originDateStr = new SimpleDateFormat("yyMMdd").format(currentTime ); 
  5. //計(jì)算當(dāng)前時(shí)間走過(guò)的秒 
  6. Date startTime =  new SimpleDateFormat("yyyyMMdd").parse(new SimpleDateFormat("yyyyMMdd").format(originDate)); 
  7. long differSecond = (currentTime.getTime() - startTime.getTime()) / 1000; 
  8. //獲取【年的后2位+月+日+秒】,秒的長(zhǎng)度不足補(bǔ)充0 
  9. String yyMMddSecond = originDateStr +  StringUtils.leftPad(String.valueOf(differSecond), 5, '0'); 
  10.  
  11. //獲取【業(yè)務(wù)編碼】 + 【年的后2位+月+日+秒】,作為自增key; 
  12. String prefixOrder = sourceType + "" + yyMMddSecond; 
  13. //通過(guò)key,采用redis自增函數(shù),實(shí)現(xiàn)單秒自增;不同的key,從0開(kāi)始自增,同時(shí)設(shè)置60秒過(guò)期 
  14. Long incrId = redisUtils.saveINCR(prefixComplaint, 60); 
  15. //生成訂單編號(hào) 
  16. String orderNo = prefixOrder + StringUtils.leftPad(String.valueOf(incrId), 4, '0'); 

此訂單編號(hào)可以保證大流量環(huán)境下全局唯一、生成速度非常的快、支持高并發(fā)環(huán)境,同時(shí)還支持按時(shí)間排序!

三、總結(jié)

通過(guò)上面的示例演示,我們可用做一個(gè)詳細(xì)的總結(jié)!

綜上所述,在大流量的環(huán)境下,我們可以通過(guò) redis 的incr函數(shù)實(shí)現(xiàn)序列號(hào)自增的特性,同時(shí)搭配訂單的設(shè)計(jì)規(guī)則,從而保證高并發(fā)的環(huán)境下,訂單唯一性!

四、參考

1、如何正確設(shè)計(jì)一個(gè)訂單號(hào)??? 

2、并發(fā)下的唯一訂單號(hào)生成規(guī)則

 

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2020-10-21 12:10:30

訂單號(hào)Java代碼

2024-10-14 12:05:56

2021-07-01 06:58:12

高并發(fā)訂單號(hào)SCM

2019-08-23 08:09:18

訂單號(hào)生成數(shù)據(jù)庫(kù)ID

2024-05-13 08:37:17

炫技H5UI

2020-11-18 09:56:46

Java開(kāi)發(fā)代碼

2025-03-11 08:48:35

JVMOOM事故

2024-09-04 08:55:56

2020-07-07 14:15:25

Go代碼數(shù)據(jù)

2025-01-02 09:06:43

2020-08-24 07:34:39

網(wǎng)絡(luò)超時(shí)請(qǐng)求

2021-03-05 22:41:55

CDH集群CDH集群

2025-09-15 07:51:35

2025-11-13 07:46:10

2021-10-22 05:56:31

數(shù)據(jù)庫(kù)鎖表鎖定機(jī)制

2019-01-16 09:20:42

架構(gòu)設(shè)計(jì)JVM FullGC宕機(jī)事故

2019-03-19 09:34:41

離職跳槽月薪

2022-07-11 13:58:14

數(shù)據(jù)庫(kù)業(yè)務(wù)流程系統(tǒng)

2023-01-16 14:49:00

MongoDB數(shù)據(jù)庫(kù)

2020-11-16 12:35:25

線程池Java代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

国产一区二区三区三区在线观看| 久久精品国产精品国产精品污 | 午夜精品福利一区二区蜜股av | av污在线观看| 成人午夜av电影| 亚洲一卡二卡三卡四卡无卡网站在线看| 国产一区激情| 99高清视频有精品视频| 色999国产精品| 国产精品一区二区三区免费视频| 婷婷综合电影| 久久久久久久久久亚洲| 99热这里只有精品首页| 久久免费视频网| 午夜欧洲一区| 国产精品久久久久9999| 三上亚洲一区二区| 亚洲一区久久久| 国产一区白浆| 中文字幕一区二区中文字幕 | 欧美日本韩国在线| 亚洲一区二区免费看| 欧美精品亚洲精品| 免费精品99久久国产综合精品| 亚洲国产精品一区二区第一页| 另类成人小视频在线| 穿情趣内衣被c到高潮视频| 国产精品66部| 亚洲少妇第一页| 亚洲啪啪综合av一区二区三区| 日本高清网站| 欧美伊人精品成人久久综合97| dy888亚洲精品一区二区三区| 精品国产一区二区三区久久久蜜月 | 女人被爽到呻吟gif动态图下载| 亚洲靠逼com| 青青久在线视频免费观看| 欧美人伦禁忌dvd放荡欲情| 国产在线拍揄自揄拍视频| 亚洲网站在线观看| 久久精品国产亚洲5555| 成人免费看黄网站| 日韩不卡手机在线v区| 人人妻人人澡人人爽欧美一区双 | 国产精品色在线网站| 国产精品色婷婷视频| 亚洲毛片视频| 日韩国产精品毛片| 欧美激情一区二区三区蜜桃视频| 免费国产视频| 91精品久久久久久久99蜜桃| 久久久人成影片一区二区三区在哪下载 | 一本到12不卡视频在线dvd| 欧美日韩亚洲在线 | 欧美性做爰猛烈叫床潮| 美女视频在线免费| 欧美激情极品视频| 国产一区欧美| 久操网在线观看| 亚洲第一成人在线| 97天天综合网| 欧美最猛性xxxxx(亚洲精品)| 亚洲看片免费| 国产精品一区二区免费在线观看 | 999sesese| 欧美一卡二卡三卡| 国产精品久久久久久久久久辛辛| 国产在线视频一区| 国产精品一区二区黑丝| 97国产在线| 亚洲欧美制服中文字幕| 国产乱码精品一区二区三区四区| 鲁丝片一区二区三区| 2欧美一区二区三区在线观看视频| 91嫩草在线播放| 日韩精品免费在线播放| 日韩精品永久网址| 国产欧美日韩小视频| 色伊人久久综合中文字幕| 成人做爰视频www| 97se亚洲综合在线| 久久人人爽人人爽| 中文字幕在线观看播放| 日本欧美国产在线| 国产不卡在线视频| av免费在线一区二区三区| 欧美成人激情视频| 视频在线在亚洲| 午夜在线免费视频| 中文字幕av一区| 国产精品vip| 男人插女人欧美| 夜夜嗨av一区二区三区免费区 | 久久亚洲影视婷婷| 午夜av在线免费观看| 日本精品久久久久影院| 国产精品66部| 国产黄在线看| 国产精品视频在线观看| 色综合电影网| 一区二区三区在线免费观看| 欧美专区福利免费| 成人免费视频视频在| 国产视频亚洲色图| av资源亚洲| 久久久久久国产精品mv| 亚洲成av人片在线| 成人爽a毛片免费啪啪红桃视频| 永久久久久久| 91精品国产乱码久久蜜臀| 亚洲国产精品成人| 午夜电影福利| 91地址最新发布| 成人精品亚洲人成在线| 最新av免费在线| 日韩色av导航| 美女日韩在线中文字幕| 最新理论片影院| 午夜精品一区二区三区在线播放 | 色综合天天综合在线视频| 激情av综合| 国产视频一区二区三区在线播放 | 国产人成在线视频| 国产精品入口福利| 亚洲欧美日韩一区| 911亚洲精品| 国产视频手机在线播放| 久久九九国产精品怡红院| 成人v精品蜜桃久久一区| 这里有精品可以观看| 亚洲制服中文| 日韩高清av一区二区三区| 奇米一区二区三区| 欧美aaa免费| 亚洲va韩国va欧美va精四季| 欧美日韩一本到| 亚洲无线一线二线三线区别av| 天堂a√在线| 亚洲www视频| 日本道在线观看一区二区| 欧美色图麻豆| 黄av在线播放| 亚洲欧洲日本国产| 亚洲欧美在线看| 成人免费电影视频| 国产精品一区二区美女视频免费看 | 亚洲综合色婷婷| 国产精品99视频| 粉嫩av在线播放| 日本在线观看一区二区三区| 日韩午夜激情视频| 美足av综合网| 国产精品视频永久免费播放| 有坂深雪av一区二区精品| 国产精品一区二区av日韩在线| 黄色三级电影网站| 国产精品日韩久久久久| 欧美日韩一区二区精品| 91精品啪在线观看国产81旧版| 久草在线青青草| 欧美极品色图| 日韩精品欧美国产精品忘忧草| 国产麻豆9l精品三级站| 伊人久久大香伊蕉在人线观看热v| 精品视频一区二区在线| 2021国产精品视频| 欧美日韩激情视频| 日韩精品一卡二卡三卡四卡无卡| 亚洲成人短视频| а√最新版天堂中文在线| 成人欧美一区二区三区黑人| 91精品国产品国语在线不卡| 极品销魂美女一区二区三区| 日韩中文字幕在线一区| 福利在线国产| 久久久久资源| 精品国内自产拍在线观看| 1000精品久久久久久久久| 欧美精品自拍| 欧美激情网站| 福利视频网站| 久久99精品国产一区二区三区| 日韩久久精品一区| 92精品国产成人观看免费| 色棕色天天综合网| 亚洲奶水xxxx哺乳期| 999香蕉视频| 92裸体在线视频网站| 亚洲欧美激情另类校园| 亚洲啪啪综合av一区二区三区| 国产精品一页| 中文字幕亚洲在线观看| av电影在线观看| 欧美日韩在线视频一区二区三区| 亚洲精品欧美极品| www国产精品com| 欧美喷潮久久久xxxxx| 日本一区免费视频| 视频精品一区二区| 黑人操亚洲人|