以前一直在思考高併發環境下怎樣生成惟一訂單號,考慮過期間戳、UUID等,但都不是十分滿意,直到最近看到公司的訂單號的生成方式,感受仍是比較完美的一種解決方式。在這裏記錄一下公司的訂單號的生成方式。redis
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()方法,該方法是訂單號生成的一個亮點,也是支持可以高併發的主要緣由。app
Incr 命令會將 redis的key 中儲存的數字值增一。高併發
decr 命令會將 redis的key 中存儲的數字值減一。測試
若是 key 不存在,那麼 key 的值會先被初始化爲 0 ,而後再執行 INCR / DECR 操做。spa
若是值包含錯誤的類型,或字符串類型的值不能表示爲數字,那麼返回一個錯誤。code
以前看到過說 Incr 命令最高支持每秒1000萬級別的遞增(沒有測試過),且該命令支持原子性,用來生成訂單號來講仍是比較輕鬆的。blog
一樣的該方式也適用於 」秒殺「庫存的遞減 等場景。 字符串