訂單是整個電子商務的核心,整個電子商務的流程也是圍繞訂單展開的。本文與大家分享一下各大電子商務網站訂單號的生成方式。
訂單號
概念:它是您在購物網站購物後獲得的訂單號,記錄的是購物訂單信息。
作用:在您需要與購物網站進行訂單查詢等操作時,需要給購物網站提供商家訂單號。
下單途徑:
- web網站下單
- 打電話到呼叫中心(CallCenter)下單
- 手機wap下單
如果採用單數據庫來存儲的話,隨着訂單量的增加,單庫的寫壓力增大,造成數據庫服務器性能下降。一般會採用分庫來緩解數據庫服務器的壓力。
進行分庫:
- web來源訂單,存入web訂單庫。
- CallCenter來源訂單,存入CallCenter訂單庫。
- wap來源訂單,存入wap訂單庫。
最終,將這三種類型的數據庫同步到訂單主庫中。
把不同的訂單同步到訂單主庫:電商網站一般利用訂單號來作爲訂單表的主鍵。因此,我們必須保證訂單號不重複,才能將訂單安全的同步到訂單主庫中。
訂單命名規定
唯一性:保證訂單號不重複。
安全性:訂單編號不能透露你公司的真實運營信息,比如你的訂單就是流水號的話,那麼別人就可以從訂單號推測出你公司的整體運營概括了。所以訂單編碼必須是除了你們公司少部分人外,其他人基本看不懂的。可以參考京東和淘寶的編碼規則。
不能使用大規模隨機碼:因爲大規模的隨機碼隨機生成,因爲本身就沒有意義所以無所謂泄密了。但是事實上這種編碼規則在實現上會有很大問題的。隨機碼滿足第二點安全性要求,爲了滿足唯一性,那就得在生成隨機碼的時候對比歷史數據是否有重複,如果你的訂單數量到達了十萬次,你每次生成訂單編碼時就得對比十萬條歷史數據。
隨機碼就不能在編碼中使用了嗎?小規模的隨機碼是可以使用的,比如2~3位,這種隨機碼一般都是和流水號等結合使用,主要作用是爲了隱藏流水號的真實數據而進行使用的。
防止併發:主要針對編碼中有時間的設定。
控制位數:訂單號的作用就是便於查詢。一般正常使用場景應該是訂單出異狀或者退貨的時候,用戶將訂單號報給客服,由客服進行查詢。所以一般在10~15位爲好。目前京東11位,淘寶16位。
怎麼保證訂單號的唯一性
訂單號命名規則來生成
如“業務編碼 + 時間戳 + 機器編號[前4位] + 隨機4位數 + 毫秒數”。
說明:業務編碼(OrderType: Web=1 CallCenter=2 Wap=3) 機器編號(用來表示由那臺服務器生成的訂單)
僞代碼如下:
import org.apache.commons.lang3.RandomStringUtils;
public static String genOrderNo(OrderType type){
Date curDate = new Date();
String orderType = getType(type);
String dateStr4yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss").format(curDate);
String dateStr4SSS = new SimpleDateFormat("SSS").format(curDate);
String random = RandomStringUtils.random(4,false,true);
String machineCode = getMachineCode().substring(0,4);
return orderType+dateStr4yyyyMMddHHmmss+machineCode+random+dateStr4SSS;
}
缺點:這種方式在高併發下會頻繁更新訂單量記錄表,很容易產生鎖表。但是鎖表問題也是可以解決的,加一層緩存。
全局訂單號數據池來生成
數據庫創建一個訂單號數據庫表(order_id_generator);利用python腳本生成一批訂單號,將這批訂單號存入到order_id_generator表中。生成訂單時,會首先調用事務GET_ORDER_ID_FOR_REGISTER,獲得當前訂單號,再生成訂單。這樣就保證了子庫訂單號不會重複。
數據庫代碼如下:
CREATE TABLE `order_id_generator` (
`RANDOM_VALUE` bigint(20) NOT NULL,
`ORDER_ID` int(11) NOT NULL,
PRIMARY KEY (`RANDOM_VALUE`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP PROCEDURE IF EXISTS `GET_ORDER_ID_FOR_REGISTER`;
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `GET_ORDER_ID_FOR_REGISTER`()
BEGIN
declare userMid int default 0;
declare randomValue bigint default 0;
start transaction;
select ORDER_ID, RANDOM_VALUE into orderId, randomValue from order_id_generator limit 1 for update;
if userMid > 0 then
delete from order_id_generator where RANDOM_VALUE = randomValue;
end if;
commit;
select orderId from dual;
END
;;
DELIMITER ;
僞代碼如下:
Long getIdForOrder();
總結
訂單號的生成方案,需要根據目前的訂單量而定;因爲各種方案都有各自的使用場景。