如何通過(guò)SpringBoot實(shí)現(xiàn)商城秒殺系統(tǒng)
這篇文章主要介紹了如何通過(guò)SpringBoot實(shí)現(xiàn)商城秒殺系統(tǒng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
學(xué)習(xí)自:地址
1.主要流程
1.1數(shù)據(jù)庫(kù):

1.2 環(huán)境
window下:Zookeeper,Redis,rabbitmq-server。jdk1.8以上。
1.3 介紹
這里只做秒殺部分功能,其他功能不會(huì)涉及。項(xiàng)目運(yùn)行后可訪(fǎng)問(wèn)秒殺商品頁(yè)面

當(dāng)用戶(hù)沒(méi)登陸,點(diǎn)擊詳情會(huì)跳轉(zhuǎn)到登陸頁(yè)面。

用戶(hù)登陸后可以查看商品的詳情并進(jìn)行搶購(gòu)。

注意,用戶(hù)對(duì)于一件商品只能搶購(gòu)一次,進(jìn)行第二次搶購(gòu)時(shí)會(huì)被拒絕。當(dāng)用戶(hù)搶購(gòu)成功時(shí)會(huì)異步發(fā)送一封郵件給用戶(hù)。

主要邏輯就是以上。接下來(lái)看代碼
1.4 項(xiàng)目結(jié)構(gòu),api封裝一些枚舉和返回值,model主要是實(shí)體類(lèi)和sql映射文件,service實(shí)現(xiàn)業(yè)務(wù)邏輯代碼。




1.5 顯示秒殺商品到頁(yè)面以及用戶(hù)的操作使用的還是MVC模式,不細(xì)講。主要看如實(shí)現(xiàn)高并發(fā)下的秒殺。
要細(xì)述的話(huà),東西太多,如果想深入了解,可點(diǎn)擊上面的鏈接。
基本的秒殺邏輯如下,判斷用戶(hù)是否已經(jīng)搶購(gòu)過(guò)該商品,如果沒(méi)有則查詢(xún)待秒殺商品詳情,判斷該商品是否可以別秒殺,判斷依據(jù)為庫(kù)存是否足夠
如果符合條件,則該商品庫(kù)存減1,接著,再一次判斷扣減是否成功,如果扣減成功則生成秒殺成功的訂單,同時(shí)通知用戶(hù)秒殺成功的信息。
public Boolean killItem(Integer killId, Integer userId) throws Exception {
Boolean result=false;
//TODO:判斷當(dāng)前用戶(hù)是否已經(jīng)搶購(gòu)過(guò)當(dāng)前商品
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
//TODO:查詢(xún)待秒殺商品詳情
ItemKill itemKill=itemKillMapper.selectById(killId);
//TODO:判斷是否可以被秒殺canKill=1?
if (itemKill!=null && 1==itemKill.getCanKill() ){
//TODO:扣減庫(kù)存-減一
int res=itemKillMapper.updateKillItem(killId);
//TODO:扣減是否成功?是-生成秒殺成功的訂單,同時(shí)通知用戶(hù)秒殺成功的消息
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception("您已經(jīng)搶購(gòu)過(guò)該商品了!");
}
return result;
}
代碼優(yōu)化1:使用redis的分布式鎖,使用當(dāng)前秒殺商品的id和當(dāng)前用戶(hù)的id組成一個(gè)key,使用StringBuffer拼接,使用雪花算法生成一個(gè)value,存進(jìn)redis中。
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 商品秒殺核心業(yè)務(wù)邏輯的處理-redis的分布式鎖
* @param killId
* @param userId
* @return
* @throws Exception
*/
@Override
public Boolean killItemV3(Integer killId, Integer userId) throws Exception {
Boolean result=false;
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
//TODO:借助Redis的原子操作實(shí)現(xiàn)分布式鎖-對(duì)共享操作-資源進(jìn)行控制
ValueOperations valueOperations=stringRedisTemplate.opsForValue();
final String key=new StringBuffer().append(killId).append(userId).append("-RedisLock").toString();
final String value=RandomUtil.generateOrderCode();
Boolean cacheRes=valueOperations.setIfAbsent(key,value); //luna腳本提供“分布式鎖服務(wù)”,就可以寫(xiě)在一起
//TOOD:redis部署節(jié)點(diǎn)宕機(jī)了
if (cacheRes){
stringRedisTemplate.expire(key,30, TimeUnit.SECONDS);
try {
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}catch (Exception e){
throw new Exception("還沒(méi)到搶購(gòu)日期、已過(guò)了搶購(gòu)時(shí)間或已被搶購(gòu)?fù)戤叄?);
}finally {
if (value.equals(valueOperations.get(key).toString())){
stringRedisTemplate.delete(key);
}
}
}
}else{
throw new Exception("Redis-您已經(jīng)搶購(gòu)過(guò)該商品了!");
}
return result;
}
代碼優(yōu)化2:將 Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS); 每隔30秒判斷當(dāng)前用戶(hù)是否超時(shí)寫(xiě)在了鎖外面,不會(huì)因?yàn)橐淮慰D而影響整個(gè)程序。
@Autowired
private RedissonClient redissonClient;
/**
* 商品秒殺核心業(yè)務(wù)邏輯的處理-redisson的分布式鎖
* @param killId
* @param userId
* @return
* @throws Exception
*/
@Override
public Boolean killItemV4(Integer killId, Integer userId) throws Exception {
Boolean result=false;
final String lockKey=new StringBuffer().append(killId).append(userId).append("-RedissonLock").toString();
RLock lock=redissonClient.getLock(lockKey);
try {
Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS);
if (cacheRes){
//TODO:核心業(yè)務(wù)邏輯的處理
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception("redisson-您已經(jīng)搶購(gòu)過(guò)該商品了!");
}
}
}finally {
lock.unlock();
//lock.forceUnlock();
}
return result;
}
代碼優(yōu)化3:
@Autowired
private CuratorFramework curatorFramework;
private static final String pathPrefix="/kill/zkLock/";
/**
* 商品秒殺核心業(yè)務(wù)邏輯的處理-基于ZooKeeper的分布式鎖
* @param killId
* @param userId
* @return
* @throws Exception
*/
@Override
public Boolean killItemV5(Integer killId, Integer userId) throws Exception {
Boolean result=false;
InterProcessMutex mutex=new InterProcessMutex(curatorFramework,pathPrefix+killId+userId+"-lock");
try {
if (mutex.acquire(10L,TimeUnit.SECONDS)){
//TODO:核心業(yè)務(wù)邏輯
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception("zookeeper-您已經(jīng)搶購(gòu)過(guò)該商品了!");
}
}
}catch (Exception e){
throw new Exception("還沒(méi)到搶購(gòu)日期、已過(guò)了搶購(gòu)時(shí)間或已被搶購(gòu)?fù)戤叄?);
}finally {
if (mutex!=null){
mutex.release();
}
}
return result;
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- SpringBoot+Redis隊(duì)列實(shí)現(xiàn)Java版秒殺的示例代碼
- Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐
- 基于Redis結(jié)合SpringBoot的秒殺案例詳解
- SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))
- 基于SpringBoot構(gòu)建電商秒殺項(xiàng)目代碼實(shí)例
- springboot集成redis實(shí)現(xiàn)簡(jiǎn)單秒殺系統(tǒng)
- springboot集成開(kāi)發(fā)實(shí)現(xiàn)商場(chǎng)秒殺功能
- SpringBoot微服務(wù)實(shí)現(xiàn)秒殺搶購(gòu)代金券功能
相關(guān)文章
resty client使用Java客戶(hù)端來(lái)訪(fǎng)問(wèn)Api
這篇文章主要介紹了resty-client使用Java客戶(hù)端來(lái)訪(fǎng)問(wèn)Api的驗(yàn)證權(quán)限,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
Java中的static和final關(guān)鍵字的使用詳解
這篇文章主要介紹了Java中的static和final關(guān)鍵字的使用詳解, 當(dāng)方法名前有static,即為static方法,可以方便我們無(wú)需創(chuàng)建對(duì)象也可以調(diào)用此方法,靜態(tài)方法比較拉,只可以訪(fǎng)問(wèn) 靜態(tài)的 屬性/變量/方法,無(wú)法訪(fǎng)問(wèn)非靜態(tài)的這些屬性/變量/方法,需要的朋友可以參考下2024-01-01
java安全fastjson1.2.24反序列化TemplatesImpl分析
這篇文章主要介紹了java安全fastjson1.2.24反序列化TemplatesImpl分析,fastjson是alibaba開(kāi)源的一個(gè)用于處理json數(shù)據(jù)格式的解析庫(kù),它支持將java對(duì)象解析成json字符串格式的數(shù)據(jù),也可以將json字符串還原成java對(duì)象2022-07-07
Spring Cloud Stream微服務(wù)消息框架原理及實(shí)例解析
這篇文章主要介紹了Spring Cloud Stream微服務(wù)消息框架原理及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Springboot Thymeleaf實(shí)現(xiàn)HTML屬性設(shè)置
這篇文章主要介紹了Springboot Thymeleaf實(shí)現(xiàn)HTML屬性設(shè)置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2007-11-11
基于Docker的K8s(Kubernetes)集群部署方案
這篇文章主要介紹了基于Docker的K8s(Kubernetes)集群部署方案,文中介紹了安裝k8s的可視化界面的相關(guān)操作,需要的朋友可以參考下2024-01-01

