Redis實(shí)現(xiàn)限量?jī)?yōu)惠券的秒殺功能
核心:避免超賣問(wèn)題,保證一人一單 業(yè)務(wù)邏輯
代碼步驟分析
全部代碼
@Service public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService { @Resource private ISeckillVoucherService seckillVoucherService; @Resource private RedisIdWorker redisIdWorker; @Resource private StringRedisTemplate stringRedisTemplate; @Resource private RedissonClient redissonClient; @Override public Result seckillVoucher(Long voucherId) { //1 查詢優(yōu)惠券信息 SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId); //2 判斷秒殺是否開始 LocalDateTime now = LocalDateTime.now(); //現(xiàn)在時(shí)間 LocalDateTime beginTime = seckillVoucher.getBeginTime(); //開始時(shí)間 LocalDateTime endTime = seckillVoucher.getEndTime(); //結(jié)束時(shí)間 if (now.isBefore(beginTime)) { return Result.fail("秒殺還未開始"); } //3 判斷秒殺是否結(jié)束 if (now.isAfter(endTime)) { return Result.fail("秒殺已結(jié)束"); } //4 判斷庫(kù)存是否充足 int stock = (int) seckillVoucher.getStock(); if (stock == 0 && stock <= 0) { return Result.fail("庫(kù)存不足"); } //確保一人一單 用戶ID和代金券ID聯(lián)合查詢 Long userId = UserHolder.getUser().getId(); //先獲取鎖 再提交事務(wù) //synchronized (userId.toString().intern()) { //創(chuàng)建鎖對(duì)象 //SimpleRedisLock simpleRedisLock = new SimpleRedisLock("order:" + userId, stringRedisTemplate); RLock lock = redissonClient.getLock("lock:order:" + userId); //獲取鎖 boolean isLock = lock.tryLock(); //判斷是否獲取鎖成功 if (!isLock){ //獲取鎖失敗 返回錯(cuò)誤或失敗 return Result.fail("不允許重復(fù)下單"); } try { //獲取事務(wù)的代理對(duì)象 IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy(); return proxy.creatVoucherOrder(voucherId); } finally { //釋放鎖 lock.unlock(); } //}//事務(wù)提交之后在釋放鎖 } /** * 這里對(duì)于加鎖做出一些解釋:如果鎖加在整個(gè)方法上,那么就會(huì)導(dǎo) * 致鎖的粒度過(guò)大,導(dǎo)致每個(gè)進(jìn)程進(jìn)來(lái)都會(huì)鎖住,所以要控制鎖的粒度 */ @Transactional public Result creatVoucherOrder(Long voucherId) { Long userId = UserHolder.getUser().getId(); Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count(); if (count > 0) { return Result.fail("用戶已經(jīng)購(gòu)買過(guò)了"); } //5 扣減庫(kù)存- boolean success = seckillVoucherService.update() .setSql("stock = stock -1 ") //樂(lè)觀鎖 .eq("voucher_id", voucherId).gt("stock", 0) //判斷庫(kù)存是否大于0: where id = ? and stock > 0 .update(); if (!success) { return Result.fail("庫(kù)存不足"); } //6 創(chuàng)建訂單 //6.1 訂單ID VoucherOrder voucherOrder = new VoucherOrder(); long orderid = RedisIdWorker.nextId("order"); voucherOrder.setVoucherId(orderid); //6.2 用戶ID voucherOrder.setUserId(userId); //6.3 代金券ID voucherOrder.setVoucherId(voucherId); save(voucherOrder); //7 返回訂單id return Result.ok(orderid); } }
到此這篇關(guān)于Redis實(shí)現(xiàn)限量?jī)?yōu)惠券的秒殺功能的文章就介紹到這了,更多相關(guān)Redis優(yōu)惠券秒殺內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)分布式鎖和等待序列的方法示例
這篇文章主要介紹了Redis實(shí)現(xiàn)分布式鎖和等待序列的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-06-06虛擬機(jī)下的Redis無(wú)法訪問(wèn)報(bào)錯(cuò)500解決方法
這篇文章主要介紹了虛擬機(jī)下的Redis無(wú)法訪問(wèn),報(bào)錯(cuò)500解決方法,由于我的redis是在虛擬機(jī)下安裝的,無(wú)法訪問(wèn)redis的原因是因?yàn)樘摂M機(jī)的ip地址和主機(jī)不同,文中通過(guò)圖文結(jié)合給出了詳細(xì)的解決方法,需要的朋友可以參考下2024-02-02淺談Redis位圖(Bitmap)及Redis二進(jìn)制中的問(wèn)題
這篇文章主要介紹了Redis位圖(Bitmap)及Redis二進(jìn)制中的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Redis連接池監(jiān)控(連接池是否已滿)與優(yōu)化方法
本文詳細(xì)講解了如何在Linux系統(tǒng)中監(jiān)控Redis連接池的使用情況,以及如何通過(guò)連接池參數(shù)配置、系統(tǒng)資源使用情況、Redis命令監(jiān)控、外部監(jiān)控工具等多種方法進(jìn)行檢測(cè)和優(yōu)化,以確保系統(tǒng)在高并發(fā)場(chǎng)景下的性能和穩(wěn)定性,討論了連接池的概念、工作原理、參數(shù)配置,以及優(yōu)化策略等內(nèi)容2024-09-09使用Redis實(shí)現(xiàn)點(diǎn)贊取消點(diǎn)贊的詳細(xì)代碼
這篇文章主要介紹了Redis實(shí)現(xiàn)點(diǎn)贊取消點(diǎn)贊的詳細(xì)代碼,通過(guò)查詢某實(shí)體(帖子、評(píng)論等)點(diǎn)贊數(shù)量,需要用到事務(wù)相關(guān)知識(shí),結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03redis客戶端實(shí)現(xiàn)高可用讀寫分離的方式詳解
基于sentienl 獲取和動(dòng)態(tài)感知 master、slaves節(jié)點(diǎn)信息的變化,我們的讀寫分離客戶端就能具備高可用+動(dòng)態(tài)擴(kuò)容感知能力了,接下來(lái)通過(guò)本文給大家分享redis客戶端實(shí)現(xiàn)高可用讀寫分離的方式,感興趣的朋友一起看看吧2021-07-07