1. 程式人生 > >分布式系統電商訂單號的最佳生成方式

分布式系統電商訂單號的最佳生成方式

分布式系 and nth def 分布 param 分布式系統 行程 重要

最近在研發區塊鏈支付系統,眾所周知,有支付必有訂單。今天不做支付系統的具體分析,只來談談目前較為熱門的訂單號碼生成方案!

在分布式高並發情況下,訂單號必須滿足最重要的一個條件:唯一性,訂單關系這支付明細,與支付相關的向來都是最重要的,馬虎不得。

目前較為成熟的,我所知道的有兩種生成方案,接下來做一下對比:

1、根據MySQL自增主鍵生成訂單號

首先,需要創建一張滿足自增條件的表,有兩個字段即可,id和value,id設置為自增,類型為bigint即可

eg:在mybatis框架中

<insert id="insertAndGetId" useGeneratedKeys="true"
keyProperty="id" parameterType="com.chenzhou.mybatis.User"> insert into user(userName,password,comment) values(#{userName},#{password},#{comment}) </insert>

其中useGeneratedKeys="true" 的配置就表示新增後返回主鍵id,此時我們就可以根據主鍵id做訂單唯一性標識,再加上時間201903010+自增主鍵,或其他復雜的組合方式即可

此方式的優點:關系型數據庫的可靠性!

此方式的缺點:在分布式環境下,需要保證新增的操作是單線程的,需要加鎖。

2、利用Redis非關系型數據庫

先看代碼,再解釋

 public String getOrderId(String prefix) {
        //生成訂單號 redis incr
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String time = sdf.format(new Date());
        //當天流水7位
        Long tx = redisTemplate.opsForValue().increment(CommonConstants.OUR_ORDER_ID_INCREMENT_KEY, 1);
        
if (tx < CommonConstants.ORDER_ID_INCREMENT_DEFAULT_VALUE) { //沒值,自動添加 redisTemplate.opsForValue().set(CommonConstants.OUR_ORDER_ID_INCREMENT_KEY, CommonConstants.ORDER_ID_INCREMENT_DEFAULT_VALUE); tx = redisTemplate.opsForValue().increment(CommonConstants.OUR_ORDER_ID_INCREMENT_KEY, 1); } //自動補0 String end = autoAddZero(String.valueOf(tx)); return prefix + time + end; } public String autoAddZero(String liuShuiHao) { Integer intHao = Integer.parseInt(liuShuiHao); DecimalFormat df = new DecimalFormat(CommonConstants.ORDER_ID_NUM); return df.format(intHao); }
getOrderId方法,傳入參數prefix,這是訂單前綴,有時候我們需要為不同種類或功能生成不一樣的訂單前綴以助區分,其中最主要是用到了redis的incr函數。我們都知道redis是單行程的,每次操作都不會引發臟讀的問題
因此,我們可以利用redis的自增方法incr為我們的訂單做唯一性處理。
tx < CommonConstants.ORDER_ID_INCREMENT_DEFAULT_VALUE 的判斷是由於第一次調用是沒有值的,需要設置一個初始值

autoAddZero是我寫的輔助保持訂單長度一致的方法,剩下的大寫的都是常量,根據字面意思設置即可

此方法的優點:基於緩存策略的性能上明顯提升。
此方法的缺點:redis數據需要載入硬盤,防丟失(其實也不算缺點)

如有不妥,歡迎指正!

分布式系統電商訂單號的最佳生成方式