日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

数据库并发抢红包_微信高并发抢红包秒杀实战案例

發(fā)布時(shí)間:2024/1/8 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库并发抢红包_微信高并发抢红包秒杀实战案例 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

群里有小伙伴咨詢(xún)微信紅包的架構(gòu),對(duì)于我來(lái)說(shuō),顯然是不知道的,但是寫(xiě)一個(gè)相對(duì)高并發(fā)的搶紅包案例還是完全可以的。

架構(gòu)設(shè)計(jì)

業(yè)務(wù)流程老板發(fā)紅包,此時(shí)緩存初始化紅包個(gè)數(shù),紅包金額(單位分),并異步入庫(kù)。

搶紅包,判斷緩存剩余紅包金額,剩余金額大于零則搶到紅包,否則手慢了,紅包派完了

拆紅包,根據(jù) redPacketId 獲取分布式鎖,如果獲取到鎖,紅包個(gè)數(shù)減一,如果剩余紅包個(gè)數(shù)大于零搶紅包成功、否則失敗。成功則計(jì)算紅包金額,緩存總紅包金額減去搶到的紅包金額,異步入庫(kù)、異步到賬。

數(shù)據(jù)庫(kù)設(shè)計(jì)紅包信息表

CREATE TABLE `red_racket` (

`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',

`red_packet_id` bigint(20) NOT NULL COMMENT '紅包唯一ID',

`total_amount` int(11) NOT NULL COMMENT '紅包金額單位分',

`total_packet` int(11) NOT NULL COMMENT '紅包個(gè)數(shù)',

`type` int(11) NOT NULL COMMENT '紅包類(lèi)型',

`create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',

`version` int(11) NOT NULL COMMENT '版本號(hào)',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='紅包信息表'搶紅包記錄表

CREATE TABLE `red_packet_record` (

`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',

`amount` int(11) NOT NULL COMMENT '搶到紅包的金額',

`red_packet_id` bigint(20) NOT NULL COMMENT '紅包ID',

`uid` int(11) NOT NULL COMMENT '搶到紅包用戶(hù)的用戶(hù)標(biāo)識(shí)',

`create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='搶紅包記錄表'

代碼案例

老板發(fā)了10個(gè)紅包一共200人民幣,100個(gè)人同時(shí)搶紅包,偽代碼分別為拆紅包和搶紅包相關(guān)業(yè)務(wù)邏輯。

模擬搶紅包偽代碼:

/**

* 搶紅包 拆紅包 搶到不一定能拆到

* @param redPacketId

* @return

*/

@ApiOperation(value="搶紅包二",nickname="爪哇筆記")

@PostMapping("/startTwo")

public Result startTwo(long redPacketId){

int skillNum = 100;

final CountDownLatch latch = new CountDownLatch(skillNum);//N個(gè)搶紅包

/**

* 初始化紅包數(shù)據(jù),搶紅包攔截

*/

redisUtil.cacheValue(redPacketId+"-num",10);

/**

* 初始化紅包金額,單位為分

*/

redisUtil.cacheValue(redPacketId+"-money",20000);

/**

* 模擬100個(gè)用戶(hù)搶10個(gè)紅包

*/

for(int i=1;i<=skillNum;i++){

int userId = i;

Runnable task = () -> {

/**

* 搶紅包 判斷剩余金額

*/

Integer money = (Integer) redisUtil.getValue(redPacketId+"-money");

if(money>0){

/**

* 雖然能搶到 但是不一定能拆到

* 類(lèi)似于微信的 點(diǎn)擊紅包顯示搶的按鈕

*/

Result result = redPacketService.startTwoSeckil(redPacketId,userId);

if(result.get("code").toString().equals("500")){

LOGGER.info("用戶(hù){}手慢了,紅包派完了",userId);

}else{

Double amount = DoubleUtil.divide(Double.parseDouble(result.get("msg").toString()), (double) 100);

LOGGER.info("用戶(hù){}搶紅包成功,金額:{}", userId,amount);

}

}else{

/**

* 直接顯示手慢了,紅包派完了

*/

//LOGGER.info("用戶(hù){}手慢了,紅包派完了",userId);

}

latch.countDown();

};

executor.execute(task);

}

try {

latch.await();

Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());

LOGGER.info("剩余金額:{}",restMoney);

} catch (InterruptedException e) {

e.printStackTrace();

}

return Result.ok();

}

業(yè)務(wù)層拆紅包:

@Override

@Transactional

public Result startTwoSeckil(long redPacketId, int userId) {

Integer money = 0;

boolean res=false;

try {

/**

* 獲取鎖 保證紅包數(shù)量和計(jì)算紅包金額的原子性操作

*/

res = RedissLockUtil.tryLock(redPacketId+"", TimeUnit.SECONDS, 3, 10);

if(res){

long restPeople = redisUtil.decr(redPacketId+"-num",1);

if(restPeople>=0){

/**

* 如果是最后一人

*/

if(restPeople==0){

money = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());

}else{

Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());

Random random = new Random();

//隨機(jī)范圍:[1,剩余人均金額的兩倍]

money = random.nextInt((int) (restMoney / (restPeople+1) * 2 - 1)) + 1;

}

redisUtil.decr(redPacketId+"-money",money);

/**

* 異步入庫(kù)

*/

RedPacketRecord record = new RedPacketRecord();

record.setMoney(money);

record.setRedPacketId(redPacketId);

record.setUid(userId);

record.setCreateTime(new Timestamp(System.currentTimeMillis()));

saveRecord(record);

/**

* 異步入賬

*/

}else{

return Result.error("手慢了,紅包派完了");

}

}else{

/**

* 獲取鎖失敗相當(dāng)于搶紅包失敗

*/

return Result.error("手慢了,紅包派完了");

}

} catch (Exception e) {

e.printStackTrace();

}finally {

if(res){//釋放鎖

RedissLockUtil.unlock(redPacketId+"");

}

}

return Result.ok(money);

}

演示

在 Application中有接口演示說(shuō)明,你可以在搶紅包 Red Packet Controller接口中輸入任何參數(shù)進(jìn)行測(cè)試,也可以配合數(shù)據(jù)庫(kù)稍加修改即可作為生產(chǎn)環(huán)境的搶紅包功能模塊。

小結(jié)

以上方案并沒(méi)有實(shí)現(xiàn)持久化和分布式,生產(chǎn)環(huán)境可根據(jù)實(shí)際業(yè)務(wù)需求選擇使用。

源碼

總結(jié)

以上是生活随笔為你收集整理的数据库并发抢红包_微信高并发抢红包秒杀实战案例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。