订单模块
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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>
|
@@ -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);
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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>
|
@@ -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
|
||||
|
Reference in New Issue
Block a user