Redis實現(xiàn)限量優(yōu)惠券的秒殺功能
更新時間:2024年12月03日 10:18:25 作者:mxbb.
文章詳細分析了避免超賣問題的方法,包括確保一人一單的業(yè)務(wù)邏輯,并提供了代碼實現(xià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)在時間
LocalDateTime beginTime = seckillVoucher.getBeginTime(); //開始時間
LocalDateTime endTime = seckillVoucher.getEndTime(); //結(jié)束時間
if (now.isBefore(beginTime)) {
return Result.fail("秒殺還未開始");
}
//3 判斷秒殺是否結(jié)束
if (now.isAfter(endTime)) {
return Result.fail("秒殺已結(jié)束");
}
//4 判斷庫存是否充足
int stock = (int) seckillVoucher.getStock();
if (stock == 0 && stock <= 0) {
return Result.fail("庫存不足");
}
//確保一人一單 用戶ID和代金券ID聯(lián)合查詢
Long userId = UserHolder.getUser().getId();
//先獲取鎖 再提交事務(wù)
//synchronized (userId.toString().intern()) {
//創(chuàng)建鎖對象
//SimpleRedisLock simpleRedisLock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);
RLock lock = redissonClient.getLock("lock:order:" + userId);
//獲取鎖
boolean isLock = lock.tryLock();
//判斷是否獲取鎖成功
if (!isLock){
//獲取鎖失敗 返回錯誤或失敗
return Result.fail("不允許重復下單");
}
try {
//獲取事務(wù)的代理對象
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
return proxy.creatVoucherOrder(voucherId);
} finally {
//釋放鎖
lock.unlock();
}
//}//事務(wù)提交之后在釋放鎖
}
/**
* 這里對于加鎖做出一些解釋:如果鎖加在整個方法上,那么就會導
* 致鎖的粒度過大,導致每個進程進來都會鎖住,所以要控制鎖的粒度
*/
@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)購買過了");
}
//5 扣減庫存-
boolean success = seckillVoucherService.update()
.setSql("stock = stock -1 ") //樂觀鎖
.eq("voucher_id", voucherId).gt("stock", 0) //判斷庫存是否大于0: where id = ? and stock > 0
.update();
if (!success) {
return Result.fail("庫存不足");
}
//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實現(xiàn)限量優(yōu)惠券的秒殺功能的文章就介紹到這了,更多相關(guān)Redis優(yōu)惠券秒殺內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis數(shù)據(jù)結(jié)構(gòu)-跳躍表skiplist詳解
這篇文章主要介紹了Redis數(shù)據(jù)結(jié)構(gòu)-跳躍表skiplist,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-09-09
基于Redis 實現(xiàn)網(wǎng)站PV/UV數(shù)據(jù)統(tǒng)計
PV和UV是兩個重要的指標,本文主要介紹了基于Redis 實現(xiàn)網(wǎng)站PV/UV數(shù)據(jù)統(tǒng)計,具有一定的參考價值,感興趣的可以了解一下2025-04-04
redis和redission分布式鎖原理及區(qū)別說明
文章對比了synchronized、樂觀鎖、Redis分布式鎖及Redission鎖的原理與區(qū)別,指出在集群環(huán)境下synchronized失效,樂觀鎖存在數(shù)據(jù)庫性能瓶頸,而Redission通過watchdog自動續(xù)期和Lua原子操作解決Redis鎖的超時問題,推薦其在高并發(fā)場景下的可靠性與易用性2025-08-08

