最近做的乙個專案有這麼乙個需求:需要生成乙個唯一的11位的就餐碼(類似於訂單號的概念),就餐碼的規則是:一共是11位的數字,前面6位是日期比如2023年07月20就是190720,後面五位是隨機數且不能是自增的,不然容易讓人看出一天的單量。
五位隨機數不能用隨機生成的,不然可能不唯一,所以想到了預生成的方案:
採用redis
先生成10000~99999共9萬個數(從1萬開始是懶得再前面補0了),然後打亂分別 存入redis的list資料結構 90個key每個key存1000個數。取的時候通過lindex進行讀取。
listnumlist=new arraylist<>();
//90萬個數 每個redis key 1000個數,要存90個key.
for (int i=10000;i<=99999;i++)
//打亂順序
collections.shuffle(numlist);
//生成key
for (int j=10;j<=99;j++)
這樣每個key的index值就是0~999,key就是qrcode:10/qrcode:11/qrcode:12.../qrcode:99.
再使用乙個key來計數每次生成乙個就餐碼就加1,值也從10000開始,計數的前兩位用來表示該取哪個key,後三位代表key的索引。比如現在計數記到12151那就是取上面生成的qrcode:12key裡索引為151的value,然後當計數到99999時再從10000重新計數,這樣保證一天有9萬個隨機數可以使用且不會取到相同的隨機數。這樣可以解決一天最多9萬單數量級的業務,後面一天百萬級同理可以擴充成6位7位等。
先初始化:
jediscluster.set(qrcode:incr,9999);
示例
public string getoneqrcode()
system.out.println("incr:"+incr);
//取前兩位
string key = incr.tostring().substring(0, 2);
//取後三位作為list裡的index
integer index = numberutil.getintvalue(incr.tostring().substring(2));
//獲得5位隨機數
string qrcode = jediscluster.lindex("qrcode:"+ key, index);
return qrcode;
}
當計數到最大值時,需要重置計數key(qrcode:incr)為10000會有執行緒不安全的問題。
我們先編寫乙個併發方法單元測試一下:
測試環境由於只生成10000個隨機數,maxincr=19999,所以
我們先把計數的key設定成接近maxincr來進行併發測試,設定成19997後獲取2個qrcode將進行重置成10000.
jediscluster.set(qrcode:incr,19997);
開啟5個執行緒併發測試:
private static final int threadnum=5;
//倒計數器,用於模擬高併發
private countdownlatch countdownlatch=new countdownlatch(threadnum);
@test
public void benchmark()
5個執行緒併發測試的結果:對qrcode:incr進行get返回的結果是10003.
獲取的結果為:
一切正常。
我的部落格位址
如何生成隨機的唯一編碼
通常來講,oracle中生成隨機唯一編碼的方法就是呼叫sys guid 函式產生16進製制的16個字元的字串,如果用varchar2來儲存guid格式的字串,那就需要32個位元組,如果我們的編碼表的資料量很大,比如 的會員資訊表,其它的業務流水表會非常多地引用會員資訊表的主鍵,這個對儲存成本要求是非...
QT 生成唯一的隨機碼
void setrandstring qstring randstring randstring str 2019 1 23 開發中發現,如果開了執行緒,在不同的執行緒中同時生產隨機碼,生成的隨機碼可能一樣。這是因為這句 引起的 qsrand t.msec t.second 1000 設定隨機數的種...
採用PHP函式uniqid生成乙個唯一的ID
php內建函式研究系列第七期,採用php函式uniqid生成乙個唯一的id,主要討論uniqid 函式的作用和用法。生成唯一id的應用場景非常普遍,如臨時快取檔名稱,臨時變數,臨時安全碼等,uniqid 函式基於以微秒計的當前時間,生成乙個唯一的 id。由於生成唯一id與微秒時間關聯,因此id的唯一...