订单模块

This commit is contained in:
2023-10-13 10:24:32 +08:00
parent 2a39b11337
commit 1d6ed7f564
90 changed files with 2862 additions and 65 deletions

View File

@@ -5,6 +5,7 @@ import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.product.service.CategoryService;
import com.atguigu.ssyx.product.service.SkuInfoService;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import com.atguigu.ssyx.vo.product.SkuStockLockVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -75,4 +76,11 @@ public class ProductInnnerController {
public SkuInfoVo getSkuInfoVo(@PathVariable Long skuId) {
return skuInfoService.getSkuInfoVo(skuId);
}
@ApiOperation(value = "验证和锁定库存")
@PostMapping("inner/checkAndLock/{orderNo}")
public Boolean checkAndLock(@RequestBody List<SkuStockLockVo> skuStockLockVoList,
@PathVariable String orderNo) {
return skuInfoService.checkAndLock(skuStockLockVoList, orderNo);
}
}

View File

@@ -2,6 +2,7 @@ package com.atguigu.ssyx.product.mapper;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
@@ -13,4 +14,29 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface SkuInfoMapper extends BaseMapper<SkuInfo> {
/**
* 验证库存
*
* @param skuId
* @param skuNum
* @return
*/
SkuInfo checkStock(@Param("skuId") Long skuId, @Param("skuNum") Integer skuNum);
/**
* 锁订库存
*
* @param skuId
* @param skuNum
* @return
*/
Integer lockStock(@Param("skuId") Long skuId, @Param("skuNum") Integer skuNum);
/**
* 解锁库存
*
* @param skuId
* @param skuNum
*/
void unlockStock(@Param("skuId") Long skuId, @Param("skuNum") Integer skuNum);
}

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ssyx.product.mapper.SkuInfoMapper">
</mapper>

View File

@@ -3,6 +3,7 @@ package com.atguigu.ssyx.product.service;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.vo.product.SkuInfoQueryVo;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import com.atguigu.ssyx.vo.product.SkuStockLockVo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -105,4 +106,13 @@ public interface SkuInfoService extends IService<SkuInfo> {
* @return
*/
List<SkuInfo> findNewPersonSkuInfoList();
/**
* 验证和锁定库存
*
* @param skuStockLockVoList
* @param orderNo
* @return
*/
Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo);
}

View File

@@ -1,5 +1,8 @@
package com.atguigu.ssyx.product.service.impl;
import com.atguigu.ssyx.common.constant.RedisConst;
import com.atguigu.ssyx.common.exception.SsyxException;
import com.atguigu.ssyx.common.result.ResultCodeEnum;
import com.atguigu.ssyx.model.product.SkuAttrValue;
import com.atguigu.ssyx.model.product.SkuImage;
import com.atguigu.ssyx.model.product.SkuInfo;
@@ -13,12 +16,16 @@ import com.atguigu.ssyx.product.service.SkuInfoService;
import com.atguigu.ssyx.product.service.SkuPosterService;
import com.atguigu.ssyx.vo.product.SkuInfoQueryVo;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import com.atguigu.ssyx.vo.product.SkuStockLockVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@@ -46,6 +53,12 @@ public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> impl
@Autowired
private RabbitService rabbitService;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
/**
* 获取sku分页列表
*
@@ -134,6 +147,7 @@ public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> impl
/**
* 修改商品sku信息
*
* @param skuInfoVo
*/
@Override
@@ -304,6 +318,75 @@ public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> impl
return skuInfoPage.getRecords();
}
/**
* 验证和锁定库存
*
* @param skuStockLockVoList
* @param orderNo
* @return
*/
@Override
public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {
//1 判断skuStockLockVoList集合是否为空
if (CollectionUtils.isEmpty(skuStockLockVoList)) {
throw new SsyxException(ResultCodeEnum.DATA_ERROR);
}
//2 遍历skuStockLockVoList得到每个商品验证库存并锁定库存具备原子性
skuStockLockVoList.stream()
.forEach(skuStockLockVo -> {
this.checkLock(skuStockLockVo);
});
//3 只要有一个商品锁定失败,所有锁定成功的商品都解锁
boolean flag = skuStockLockVoList.stream()
.anyMatch(skuStockLockVo -> !skuStockLockVo.getIsLock());
if (flag) {
//所有锁定成功的商品都解锁
skuStockLockVoList.stream()
.filter(SkuStockLockVo::getIsLock)
.forEach(skuStockLockVo -> {
baseMapper.unlockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
});
//返回失败的状态
return false;
}
//4 如果所有商品都锁定成功了redis缓存相关数据为了方便后面解锁和减库存
redisTemplate.opsForValue()
.set(RedisConst.SROCK_INFO + orderNo, skuStockLockVoList);
return true;
}
//2 遍历skuStockLockVoList得到每个商品验证库存并锁定库存具备原子性
private void checkLock(SkuStockLockVo skuStockLockVo) {
//获取锁
//公平锁
RLock rLock = this.redissonClient.getFairLock(RedisConst.SKUKEY_PREFIX + skuStockLockVo.getSkuId());
//加锁
rLock.lock();
try {
//验证库存
SkuInfo skuInfo = baseMapper.checkStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
//判断没有满足条件商品设置isLock值false返回
if (skuInfo == null) {
skuStockLockVo.setIsLock(false);
return;
}
//有满足条件商品
//锁定库存:update
Integer rows = baseMapper.lockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
if (rows == 1) {
skuStockLockVo.setIsLock(true);
}
} finally {
//解锁
rLock.unlock();
}
}
//获取商品sku信息
private SkuInfoVo getSkuInfoDB(Long skuId) {
SkuInfoVo skuInfoVo = new SkuInfoVo();

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ssyx.product.mapper.SkuInfoMapper">
<resultMap id="skuInfoMap" type="com.atguigu.ssyx.model.product.SkuInfo" autoMapping="true"></resultMap>
<!--//验证库存-->
<select id="checkStock" resultMap="skuInfoMap">
select id,
category_id,
sku_type,
sku_name,
img_url,
per_limit,
publish_status,
check_status,
is_new_person,
sort,
sku_code,
price,
market_price,
stock,
lock_stock,
low_stock,
sale,
ware_id,
create_time,
update_time,
is_deleted
from sku_info
where id = #{skuId}
and stock - lock_stock > #{skuNum} for
update
</select>
<!--//锁定库存:update-->
<update id="lockStock">
update sku_info
set lock_stock = lock_stock + #{skuNum}
where id = #{skuId}
</update>
<!--//解锁库存-->
<update id="unlockStock">
update sku_info
set lock_stock = lock_stock - #{skuNum}
where id = #{skuId}
</update>
<!--减库存-->
<update id="minusStock">
update sku_info
set stock = stock - #{skuNum},
lock_stock = lock_stock - #{skuNum},
sale = sale + #{skuNum}
where id = #{skuId}
</update>
</mapper>

View File

@@ -24,7 +24,18 @@ spring:
prefetch: 1
concurrency: 3
acknowledge-mode: manual #消费端手动确认
redis:
host: 82.157.68.223
port: 6379
database: 0
timeout: 1800000
password:
lettuce:
pool:
max-active: 20 #最大连接数
max-wait: -1 #最大阻塞等待时间(负数表示没限制)
max-idle: 5 #最大空闲
min-idle: 0 #最小空闲
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8