asp按时间自动递增编号_Java秒杀系统实战系列-分布式唯一ID生成订单编号
本文是“Java秒殺系統(tǒng)實(shí)戰(zhàn)系列文章”的第七篇,在本文中我們將重點(diǎn)介紹 “在高并發(fā),如秒殺的業(yè)務(wù)場(chǎng)景下如何生成全局唯一、趨勢(shì)遞增的訂單編號(hào)”,我們將介紹兩種方法,一種是傳統(tǒng)的采用隨機(jī)數(shù)生成的方式,另外一種是采用當(dāng)前比較流行的“分布式唯一ID生成算法-雪花算法”來(lái)實(shí)現(xiàn)。
在上一篇文章,我們完成了商品秒殺業(yè)務(wù)邏輯的代碼實(shí)戰(zhàn),在該代碼中,我們還實(shí)現(xiàn)了“當(dāng)用戶秒殺成功后,需要在數(shù)據(jù)庫(kù)表中為其生成一筆秒殺成功的訂單記錄”的功能,其對(duì)應(yīng)的代碼如下所示:
//通用的方法-記錄用戶秒殺成功后生成的訂單-并進(jìn)行異步郵件消息的通知private void commonRecordKillSuccessInfo(ItemKillkill, Integer userId) throws Exception{ //TODO:記錄搶購(gòu)成功后生成的秒殺訂單記錄 ItemKillSuccess entity=new ItemKillSuccess(); //此處為訂單編號(hào)的生成邏輯 String orderNo=String.valueOf(snowFlake.nextId()); //entity.setCode(RandomUtil.generateOrderCode()); //傳統(tǒng)時(shí)間戳+N位隨機(jī)數(shù) entity.setCode(orderNo);//雪花算法 entity.setItemId(kill.getItemId()); entity.setKillId(kill.getId()); entity.setUserId(userId.toString()); entity.setStatus(SysConstant.OrderStatus.SuccessNotPayed.getCode().byteValue()); entity.setCreateTime(DateTime.now().toDate()); //TODO:學(xué)以致用,舉一反三 -> 仿照單例模式的雙重檢驗(yàn)鎖寫法 if (itemKillSuccessMapper.countByKillUserId(kill.getId(),userId)<= 0){ intres=itemKillSuccessMapper.insertSelective(entity); //其他邏輯省略 }}在該實(shí)現(xiàn)邏輯中,其核心要點(diǎn)在于“在高并發(fā)的環(huán)境下,如何高效的生成訂單編號(hào)”,那么如何才算是高效呢?Debug認(rèn)為應(yīng)該滿足以下兩點(diǎn):
1、保證訂單編號(hào)的生成邏輯要快、穩(wěn)定,減少時(shí)延;
2、要保證生成的訂單編號(hào)全局唯一、不重復(fù)、趨勢(shì)遞增、有時(shí)序性。
下面,我們采用兩種方式來(lái)生成“訂單編號(hào)”,并自己寫一個(gè)多線程的程序模擬生成的訂單編號(hào)是否滿足條件。
值得一提的是,為了能直觀的觀察多線程并發(fā)生成的訂單編號(hào)是否具有唯一性、趨勢(shì)遞增,在這里Debug借助了一張數(shù)據(jù)庫(kù)表 random_code來(lái)存儲(chǔ)生成的訂單編號(hào),其DDL如下所示:
CREATE TABLE `random_code` ( `id`int(11) NOT NULL AUTO_INCREMENT, `code`varchar(255) DEFAULT NULL, PRIMARY KEY(`id`), UNIQUE KEY`idx_code` (`code`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8;從該數(shù)據(jù)庫(kù)表數(shù)據(jù)結(jié)構(gòu)定義語(yǔ)句中可以看出,我們?cè)O(shè)定了 訂單編號(hào)字段code 為唯一!所以如果高并發(fā)多線程生成的訂單編號(hào)出現(xiàn)重復(fù),那么在插入數(shù)據(jù)庫(kù)表的時(shí)候必然會(huì)出現(xiàn)錯(cuò)誤。
下面,首先開始我們的第一種方式吧:基于隨機(jī)數(shù)的方式生成訂單編號(hào)。
(1)首先是建立一個(gè)Thread類,其run方法的執(zhí)行邏輯為生成訂單編號(hào),并將生成的訂單編號(hào)插入數(shù)據(jù)庫(kù)表中,其代碼如下所示:
/** * 隨機(jī)數(shù)生成的方式-Thread * @Author:debug (SteadyJack) * @Date:2019/7/11 10:30 **/public class CodeGenerateThread implementsRunnable{ private RandomCodeMapper randomCodeMapper; public CodeGenerateThread(RandomCodeMapper randomCodeMapper) { this.randomCodeMapper = randomCodeMapper; } @Override public void run() { //生成訂單編號(hào)并插入數(shù)據(jù)庫(kù) RandomCode entity=new RandomCode(); entity.setCode(RandomUtil.generateOrderCode()); randomCodeMapper.insertSelective(entity); }}其中,RandomUtil.generateOrderCode()的生成邏輯是借助ThreadLocalRandom來(lái)實(shí)現(xiàn)的,其完整的源代碼如下所示:
/** * 隨機(jī)數(shù)生成util * @Author:debug (SteadyJack) * @Date:2019/6/20 21:05 **/public class RandomUtil { private static final SimpleDateFormat dateFormatOne=newSimpleDateFormat("yyyyMMddHHmmssSS"); private static final ThreadLocalRandom random=ThreadLocalRandom.current(); //生成訂單編號(hào)-方式一 public static String generateOrderCode(){ //TODO:時(shí)間戳+N為隨機(jī)數(shù)流水號(hào) return dateFormatOne.format(DateTime.now().toDate()) + generateNumber(4); } //N為隨機(jī)數(shù)流水號(hào) public static String generateNumber(final int num){ StringBuffer sb=new StringBuffer(); for(int i=1;i<=num;i++){ sb.append(random.nextInt(9)); } return sb.toString(); }}(2)緊接著是在 BaseController控制器 中開發(fā)一個(gè)請(qǐng)求方法,目的正是用來(lái)模擬前端高并發(fā)觸發(fā)產(chǎn)生多線程并生成訂單編號(hào)的邏輯,在這里我們暫且用1000個(gè)線程進(jìn)行模擬,其源代碼如下所示:
@Autowiredprivate RandomCodeMapper randomCodeMapper;//測(cè)試在高并發(fā)下多線程生成訂單編號(hào)-傳統(tǒng)的隨機(jī)數(shù)生成方法@RequestMapping(value ="/code/generate/thread總結(jié)
以上是生活随笔為你收集整理的asp按时间自动递增编号_Java秒杀系统实战系列-分布式唯一ID生成订单编号的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样做到不浪费食品调味料?
- 下一篇: java 写文件 异常 磁盘空间满_系统