Commit d2f71d4a authored by liwei's avatar liwei

修改了库存扣减lua脚本,增加了男生女生人数扣减,修改了发布活动

parent fb384429
......@@ -44,7 +44,7 @@ public class AppActivityController extends CyPaginationController<CmsActivity> {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsActivityServiceImpl.findById(businessId));
cmsActivityServiceImpl.findById(businessId,"app"));
}
/**
......
......@@ -87,7 +87,7 @@ public class CmsActivityController extends CyPaginationController<CmsActivity> {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsActivityServiceImpl.findById(businessId));
cmsActivityServiceImpl.findById(businessId,"web"));
}
@PreAuthorize("@cyPerm.hasPerm('sys:activity:list')")
......
......@@ -32,6 +32,10 @@ public interface CmsActivityRepository extends CyBaseMapper<CmsActivity> {
int deleteCmsActivity(@Param("businessId")Integer businessId);
//修改状态
int updateStatus(@Param("entity") CmsActivity cmsActivity);
//app查询活动详情
CmsActivity selectDetailById(@Param("businessId")Integer businessId);
//查询活动人数
CmsActivity selectPeopleCountById(@Param("businessId")Integer businessId);
//查询活动详情
CmsActivity selectById(@Param("businessId")Integer businessId);
//权重验重
......
......@@ -201,7 +201,23 @@ public class CmsActivity extends CyIdIncreEntity<CmsActivity> {
@TableField(exist = false)
private String url;
/**
* 已报名的总人数
*/
@TableField(exist = false)
private Integer alreadyApplicationCount;
/**
* 已报名的男生数量
*/
@TableField(exist = false)
private Integer alreadyMaleCount;
/**
* 已报名的女生数量
*/
@TableField(exist = false)
private Integer alreadyFemaleCount;
}
......
......@@ -38,7 +38,7 @@ public interface CmsActivityService {
* @param id
* @return
*/
CmsActivity findById(Integer id);
CmsActivity findById(Integer id,String type);
/**
* 分页查询 活动
......
......@@ -9,6 +9,8 @@ import lombok.extern.slf4j.Slf4j;
import org.rcisoft.business.cmsActivity.dao.CmsActivityRepository;
import org.rcisoft.business.cmsActivity.entity.CmsActivity;
import org.rcisoft.business.cmsActivity.service.CmsActivityService;
import org.rcisoft.business.cmsApplication.dao.CmsApplicationRepository;
import org.rcisoft.business.cmsApplication.entity.CmsApplication;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.core.exception.CyServiceException;
import org.rcisoft.core.model.CyPageInfo;
......@@ -50,6 +52,8 @@ public class CmsActivityServiceImpl extends ServiceImpl<CmsActivityRepository, C
private RedissonClient redissonClient;
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private CmsApplicationRepository cmsApplicationRepository;
/**
* 保存 活动
*
......@@ -109,9 +113,16 @@ public class CmsActivityServiceImpl extends ServiceImpl<CmsActivityRepository, C
* @return
*/
@Override
public CmsActivity findById(Integer id) {
CmsActivity cmsActivity = baseMapper.selectById(id);
return cmsActivity;
public CmsActivity findById(Integer id,String type) {
if (type.equals("app")){
//小程序
CmsActivity cmsActivity = baseMapper.selectDetailById(id);
return cmsActivity;
} else {
//管理端
CmsActivity cmsActivity = baseMapper.selectById(id);
return cmsActivity;
}
}
/**
......@@ -186,9 +197,13 @@ public class CmsActivityServiceImpl extends ServiceImpl<CmsActivityRepository, C
line = baseMapper.updateById(info);
Date endTime = TimeUtil.getTime(info.getEndTime(), Calendar.DATE,1);
//将活动信息插入redis
//查询已报名的数量和男生数量女生数量
CmsActivity cmsActivity = baseMapper.selectPeopleCountById(businessId);
long time = TimeUtil.getTimeSecond(new Date(),endTime);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_DETAIL +":"+ businessId,info,time);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT +":"+ businessId,info.getMaxApplicationCount(),time);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT +":"+ businessId,info.getMaxApplicationCount() - cmsActivity.getAlreadyApplicationCount(),time);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT_MALE +":"+ businessId,info.getMaleCount() - cmsActivity.getAlreadyMaleCount(),time);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT_FEMALE +":"+ businessId,info.getFemaleCount() - cmsActivity.getAlreadyFemaleCount(),time);
} else {
//如果取消发布,加redis锁
boolean isGetLock = false;
......@@ -205,6 +220,8 @@ public class CmsActivityServiceImpl extends ServiceImpl<CmsActivityRepository, C
line = baseMapper.updateById(info);
redisTemplate.delete(RedisCons.ACTIVITY_DETAIL +":"+ businessId);
redisTemplate.delete(RedisCons.ACTIVITY_COUNT +":"+ businessId);
redisTemplate.delete(RedisCons.ACTIVITY_COUNT_MALE +":"+ businessId);
redisTemplate.delete(RedisCons.ACTIVITY_COUNT_FEMALE +":"+ businessId);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
......
......@@ -2,7 +2,11 @@ package org.rcisoft.business.cmsActivity.service.impl;
import cn.hutool.core.lang.Assert;
import org.apache.commons.lang3.StringUtils;
import org.rcisoft.business.cmsActivity.dao.CmsActivityRepository;
import org.rcisoft.business.cmsActivity.entity.CmsActivity;
import org.rcisoft.business.memInfo.dao.MemInfoRepository;
import org.rcisoft.core.service.CyRedisService;
import org.rcisoft.core.util.CyUserUtil;
import org.rcisoft.core.util.IStockCallback;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
......@@ -46,10 +50,22 @@ public class StockService {
@Autowired(required = false)
private CyRedisService cyRedisServiceImpl;
@Autowired
private MemInfoRepository memInfoRepository;
@Autowired
private CmsActivityRepository activityRepository;
/**
* 执行扣库存的脚本
*/
public static final String STOCK_LUA;
/**
* 执行扣库存和男生人数的脚本
*/
public static final String STOCK_LUA2;
/**
* 执行扣库存和女生人数的脚本
*/
public static final String STOCK_LUA3;
@Value("${spring.data.redis.host}")
......@@ -97,6 +113,76 @@ public class StockService {
sb.append("end;");
sb.append("return -3;");
STOCK_LUA = sb.toString();
/**
*
* @desc 扣减库存Lua脚本
* 库存(stock)-1:表示不限库存
* 库存(stock)0:表示没有库存
* 库存(stock)大于0:表示剩余库存
*
* @params 库存key
* @return
* -3:库存未初始化
* -2:库存不足
* -1:不限库存
* 大于等于0:剩余库存(扣减之后剩余的库存)
* redis缓存的库存(value)是-1表示不限库存,直接返回1
*/
StringBuilder sb2 = new StringBuilder();
sb2.append("if (redis.call('exists', KEYS[1]) == 1 and redis.call('exists', KEYS[2]) == 1) then");
sb2.append(" local totalStock = tonumber(redis.call('get', KEYS[1]));");
sb2.append(" local maleStock = tonumber(redis.call('get', KEYS[2]));");
sb2.append(" local num = tonumber(ARGV[1]);");
sb2.append(" if (totalStock == -1) then");
sb2.append(" return -1;");
sb2.append(" end;");
sb2.append(" if (maleStock == -1) then");
sb2.append(" return -1;");
sb2.append(" end;");
sb2.append(" if (totalStock >= num and maleStock >= num) then");
sb2.append(" redis.call('incrby', KEYS[2], 0 - num);"); // 扣减男生人数
sb2.append(" return redis.call('incrby', KEYS[1], 0 - num);"); // 扣减总人数
sb2.append(" end;");
sb2.append(" return -2;"); // 库存不足
sb2.append("end;");
sb2.append("return -3;"); // 库存未初始化
STOCK_LUA2 = sb2.toString();
/**
*
* @desc 扣减库存Lua脚本
* 库存(stock)-1:表示不限库存
* 库存(stock)0:表示没有库存
* 库存(stock)大于0:表示剩余库存
*
* @params 库存key
* @return
* -3:库存未初始化
* -2:库存不足
* -1:不限库存
* 大于等于0:剩余库存(扣减之后剩余的库存)
* redis缓存的库存(value)是-1表示不限库存,直接返回1
*/
StringBuilder sb3 = new StringBuilder();
sb3.append("if (redis.call('exists', KEYS[1]) == 1 and redis.call('exists', KEYS[2]) == 1) then");
sb3.append(" local totalStock = tonumber(redis.call('get', KEYS[1]));");
sb3.append(" local maleStock = tonumber(redis.call('get', KEYS[2]));");
sb3.append(" local num = tonumber(ARGV[1]);");
sb3.append(" if (totalStock == -1) then");
sb3.append(" return -1;");
sb3.append(" end;");
sb3.append(" if (maleStock == -1) then");
sb3.append(" return -1;");
sb3.append(" end;");
sb3.append(" if (totalStock >= num and maleStock >= num) then");
sb3.append(" redis.call('incrby', KEYS[2], 0 - num);"); // 扣减女生人数
sb3.append(" return redis.call('incrby', KEYS[1], 0 - num);"); // 扣减总人数
sb3.append(" end;");
sb3.append(" return -2;"); // 库存不足
sb3.append("end;");
sb3.append("return -3;"); // 库存未初始化
STOCK_LUA3 = sb3.toString();
}
/**
......@@ -106,23 +192,28 @@ public class StockService {
* @param stockCallback 初始化库存回调函数
* @return -2:库存不足; -1:不限库存; 大于等于0:扣减库存之后的剩余库存
*/
public long stock(String key, long expire, int num, IStockCallback stockCallback) {
long stock = stock(key, num);
public long stock(String key1, String key2, String key3, long expire, int num, IStockCallback stockCallback) {
//扣总人数库存
long stock1 = stock(key1, key2, key3, num);
// 初始化库存
if (stock == UNINITIALIZED_STOCK) {
RLock redisLock = redissonClient.getLock(key);
if (stock1 == UNINITIALIZED_STOCK) {
RLock redisLock = redissonClient.getLock("reduce_activity_count");
try {
// 获取锁
if (redisLock.tryLock()) {
// 双重验证,避免并发时重复回源到数据库
stock = stock(key, num);
if (stock == UNINITIALIZED_STOCK) {
stock1 = stock(key1, key2,key3,num);
if (stock1 == UNINITIALIZED_STOCK) {
// 获取初始化库存
final int initStock = stockCallback.getStock();
// 将库存设置到redis
redisTemplate.opsForValue().set(key, initStock, expire, TimeUnit.SECONDS);
redisTemplate.opsForValue().set(key1, initStock, expire, TimeUnit.SECONDS);
// 将库存的男生人数设置到redis
redisTemplate.opsForValue().set(key2, initStock, expire, TimeUnit.SECONDS);
// 将库存的女生人数设置到redis
redisTemplate.opsForValue().set(key3, initStock, expire, TimeUnit.SECONDS);
// 调一次扣库存的操作
stock = stock(key, num);
stock1 = stock(key1, key2,key3,num);
}
}
} catch (Exception e) {
......@@ -130,9 +221,8 @@ public class StockService {
} finally {
redisLock.unlock();
}
}
return stock;
return stock1;
}
/**
......@@ -199,14 +289,22 @@ public class StockService {
/**
* 扣库存
*
* @param key 库存key
* @param key1 库存key
* @param key2 库存男生人数key
* @param key3 库存女生人数key
* @param num 扣减库存数量
* @return 扣减之后剩余的库存【-3:库存未初始化; -2:库存不足; -1:不限库存; 大于等于0:扣减库存之后的剩余库存】
*/
private Long stock(String key, int num) {
private Long stock(String key1, String key2, String key3, int num) {
// 脚本里的KEYS参数
List<String> keys = new ArrayList<>();
keys.add(key);
keys.add(key1);
List<String> keys2 = new ArrayList<>();
keys2.add(key1);
keys2.add(key2);
List<String> keys3 = new ArrayList<>();
keys3.add(key1);
keys3.add(key3);
// 脚本里的ARGV参数
List<String> args = new ArrayList<>();
args.add(Integer.toString(num));
......@@ -216,7 +314,27 @@ public class StockService {
(StringUtils.isAnyEmpty(password) ? null : password),database);){
// try (JedisPool jedisPool = new JedisPool(redisIP, Integer.parseInt(redisPort));){
Jedis jedis = jedisPool.getResource();
result = (long) jedis.evalsha(jedis.scriptLoad(STOCK_LUA), keys , args);
//获取报名人性别 截取key1的最后一个:后的值
String goodsId = key1.substring(key1.lastIndexOf(":") + 1);
CmsActivity activityInfo = activityRepository.selectById(Integer.valueOf(goodsId));
String memSex = memInfoRepository.getMemSexByUserId(Integer.valueOf(CyUserUtil.getAuthenBusinessId()));
//扣减库存总人数
if (activityInfo.getMaleCount() == 0 && activityInfo.getFemaleCount() == 0){
//活动的男女生人数都为0 不扣男女生人数
result = (long) jedis.evalsha(jedis.scriptLoad(STOCK_LUA), keys , args);
} else {
if (memSex.equals("0") && activityInfo.getMaleCount() != 0){
//报名人为男生 且男生限制人数不为0 扣除总人数和男生人数
result = (long) jedis.evalsha(jedis.scriptLoad(STOCK_LUA2), keys2 , args);
} else if (memSex.equals("1") && activityInfo.getFemaleCount() != 0){
//报名人为女生 且女生限制人数不为0 扣除总人数和女生人数
result = (long) jedis.evalsha(jedis.scriptLoad(STOCK_LUA3), keys3 , args);
} else {
//只扣除总人数
result = (long) jedis.evalsha(jedis.scriptLoad(STOCK_LUA), keys , args);
}
}
} catch (Exception e){
logger.error(e.getMessage(),e);
}
......
......@@ -136,6 +136,18 @@ public class CmsApplication extends CyIdIncreEntity<CmsApplication> {
*/
@TableField(exist = false)
private String title;
/**
* 报名的男生人数
*/
@TableField(exist = false)
private Integer maleCount;
/**
* 报名的女生人数
*/
@TableField(exist = false)
private Integer femaleCount;
}
......@@ -172,7 +172,7 @@ public class CmsOrderServiceImpl extends ServiceImpl<CmsOrderRepository,CmsOrder
Date endTime = TimeUtil.getTime(info.getEndTime(), Calendar.DATE,1);
//将活动信息插入redis
long time = TimeUtil.getTimeSecond(new Date(),endTime);
long stock = stockService.stock(RedisCons.ACTIVITY_COUNT +":"+ orderInfo.getGoodsId(), time, orderInfo.getNum(), () -> initStock(orderInfo.getGoodsId()));
long stock = stockService.stock(RedisCons.ACTIVITY_COUNT +":"+ orderInfo.getGoodsId(),RedisCons.ACTIVITY_COUNT_MALE +":"+ orderInfo.getGoodsId(),RedisCons.ACTIVITY_COUNT_FEMALE +":"+ orderInfo.getGoodsId(), time, orderInfo.getNum(), () -> initStock(orderInfo.getGoodsId()));
if (stock >= 0){ //报名成功
long orderId = cyIdGenUtil.getSnowFlakedId();
// OrderInfo orderInfo = new OrderInfo();
......@@ -224,6 +224,8 @@ public class CmsOrderServiceImpl extends ServiceImpl<CmsOrderRepository,CmsOrder
long time = TimeUtil.getTimeSecond(new Date(), endTime);
// if (info.getIsRestrictions().equals(0)) {
AtomicReference<Integer> num = new AtomicReference<>(info.getMaxApplicationCount());
AtomicReference<Integer> maleNum = new AtomicReference<>(info.getMaleCount());
AtomicReference<Integer> femaleNum = new AtomicReference<>(info.getFemaleCount());
//已报名人数计算: 数据库+ redis【order:activity:${所有}】 value 【hash】未取消 的并集
QueryWrapper<CmsOrder> wrapper = new QueryWrapper<>();
wrapper.eq("goods_id", goodsId);
......@@ -231,7 +233,18 @@ public class CmsOrderServiceImpl extends ServiceImpl<CmsOrderRepository,CmsOrder
wrapper.eq("del_flag", 0);
List<CmsOrder> orderList = baseMapper.selectList(wrapper);
for (CmsOrder orderInfo : orderList) {
//减掉数据库中订单的报名人数
num.set(num.get() - orderInfo.getNum());
//减掉数据中订单的男生报名人数或女生报名人数
//查询该报名人的性别
String memSex = memInfoRepository.getMemSexByUserId(orderInfo.getUserId());
if (memSex.equals("0")){
//男性
maleNum.set(maleNum.get() - orderInfo.getNum());
} else if (memSex.equals("1")){
//女性
femaleNum.set(femaleNum.get() - orderInfo.getNum());
}
}
List<Long> orderIds = orderList.stream().map(CmsOrder::getBusinessId).toList();
Set<String> map = redisTemplate.keys(RedisCons.ORDER_ACTIVITY + ":" + goodsId + "*");
......@@ -244,7 +257,12 @@ public class CmsOrderServiceImpl extends ServiceImpl<CmsOrderRepository,CmsOrder
num.set(num.get() - order.getNum());
});
}
//设置活动人数key
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT + ":" + goodsId, num.get(), time);
//设置活动男生人数key
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT_MALE + ":" + goodsId, maleNum.get(), time);
//设置活动女生人数key
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT_FEMALE + ":" + goodsId, femaleNum.get(), time);
return num.get();
// } else {
// cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT + ":" + goodsId, -1, time);
......
......@@ -254,5 +254,11 @@ public interface MemInfoRepository extends CyBaseMapper<MemInfo> {
* 根据手机号修改会员性别
*/
int updateMemSexByPhone(SysUserRbac var1);
/**
* 根据用户id获取用户性别
*/
String getMemSexByUserId(Integer userId);
}
......@@ -13,6 +13,10 @@ public class RedisCons {
public static final String ACTIVITY_INFO = "activity:info:";
//活动人数
public static final String ACTIVITY_COUNT = "activity:count";
//活动男生人数
public static final String ACTIVITY_COUNT_MALE = "activity:count:male";
//活动女生人数
public static final String ACTIVITY_COUNT_FEMALE = "activity:count:female";
//优惠券详情
// public static final String COUPON_DETAIL = "coupon:detail";
......
......@@ -257,4 +257,22 @@
where 1=1
and activity_id = #{businessId}
</select>
<select id="selectDetailById" resultType="org.rcisoft.business.cmsActivity.entity.CmsActivity">
select ca.*,
SUM(CASE WHEN mi.mem_sex = 0 THEN 1 ELSE 0 END) AS alreadyMaleCount,
SUM(CASE WHEN mi.mem_sex = 1 THEN 1 ELSE 0 END) AS alreadyFemaleCount
from cms_activity ca
left join cms_application cma on ca.business_id = cma.activity_id
LEFT JOIN mem_info mi ON mi.user_id = ca.create_by
where ca.business_id = #{businessId}
</select>
<select id="selectPeopleCountById" resultType="org.rcisoft.business.cmsActivity.entity.CmsActivity">
select
COUNT(mi.business_id) AS alreadyApplicationCount,
SUM(CASE WHEN mi.mem_sex = 0 THEN 1 ELSE 0 END) AS alreadyMaleCount,
SUM(CASE WHEN mi.mem_sex = 1 THEN 1 ELSE 0 END) AS alreadyFemaleCount
from cms_application ca
LEFT JOIN mem_info mi ON mi.user_id = ca.create_by
where ca.activity_id = #{businessId}
</select>
</mapper>
......@@ -145,6 +145,15 @@
</if>
ORDER BY business_id DESC
</select>
<select id="getApplicationCountByActivityId"
resultType="org.rcisoft.business.cmsApplication.entity.CmsApplication">
SELECT
SUM(CASE WHEN mi.mem_sex = 0 THEN 1 ELSE 0 END) AS maleCount,
SUM(CASE WHEN mi.mem_sex = 1 THEN 1 ELSE 0 END) AS femaleCount
FROM cms_application ca
LEFT JOIN mem_info mi ON mi.user_id = ca.create_by
WHERE ca.activity_id = #{id};
</select>
<update id="deleteCmsApplication" parameterType="java.lang.Integer">
update cms_application
......
......@@ -884,7 +884,6 @@
WHERE 1=1
AND su.business_id = #{userId}
</select>
<update id="updateMemWxByPhone" parameterType="org.rcisoft.sys.rbac.user.entity.SysUserRbac">
update mem_info
set wx_openid = #{wxOpenid}
......@@ -897,4 +896,10 @@
where 1=1
and mem_phone = #{phone}
</update>
<select id="getMemSexByUserId" resultType="java.lang.String">
select mem_sex
from mem_info
where 1=1
and user_id = #{userId}
</select>
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment