之前一直在思考高並發環境下怎樣生成唯一訂單號,考慮過時間戳、UUID等,但都不是十分滿意,直到最近看到公司的訂單號的生成方式,感覺還是比較完美的一種解決方式。在這里記錄一下公司的訂單號的生成方式。
public static long getOrderId() {
//設置訂單號前綴(可以根據數據環境/地區的不同來設置不同訂單號前綴) String ordernoIndex = PropertiesManager.getPropertiesValue("key");//從配置中心獲取訂單號前綴 if(StringUtils.isBlank(ordernoIndex)){ ordernoIndex = ""; }
//從redis中獲取訂單號 long orderId = JedisManager.incr(REDIS_ORDER_KEY, CART_REDIS_POOL);
//判斷訂單號是否小於訂單號初始值 if(orderId < orderIdInitValue){
//設置redis中orderNo的初始值 JedisManager.setString(REDIS_ORDER_KEY, String.valueOf(orderIdInitValue), 0, CART_REDIS_POOL); orderId = JedisManager.incr(REDIS_ORDER_KEY, CART_REDIS_POOL); }
//拼接訂單號(訂單前綴+redis中的自增長值),並返回 return Long.valueOf(new StringBuffer().append(ordernoIndex).append(String.valueOf(orderId)).toString()); }
訂單前綴可以設置在訂單中心或配置文件里,這樣可以在不同環境獲得不同的訂單號,避免因不同數據中心,導致出現訂單號重復的情況。
JedisManager.incr()方法,該方法是訂單號生成的一個亮點,也是支持能夠高並發的主要原因。
Incr 命令會將 redis的key 中儲存的數字值增一。
decr 命令會將 redis的key 中存儲的數字值減一。
如果 key 不存在,那么 key 的值會先被初始化為 0 ,然后再執行 INCR / DECR 操作。
如果值包含錯誤的類型,或字符串類型的值不能表示為數字,那么返回一個錯誤。
之前看到過說 Incr 命令最高支持每秒1000萬級別的遞增(沒有測試過),且該命令支持原子性,用來生成訂單號來說還是比較輕松的。
同樣的該方式也適用於 ”秒殺“庫存的遞減 等場景。