You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/**
* @author Ricky Fung
*/
@Service
public class GiftService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private StringRedisTemplate stringRedisTemplate;
private final DefaultRedisScript<Long> stockScript;
public GiftService() {
this.stockScript = new DefaultRedisScript<>();
stockScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/stock_decr.lua")));
stockScript.setResultType(Long.class);
}
/**
* 获取活动礼品库存数量
* @param giftId
* @return
*/
public int getGiftStock(Long giftId) {
String key = getActivityAwardStockKey(giftId);
String str = stringRedisTemplate.opsForValue().get(key);
int count = 0;
if (StringUtils.isNotEmpty(str)) {
count = Integer.parseInt(str);
if (count < 0) {
count = 0;
}
}
return count;
}
/**
* 扣减活动礼品库存
* @param giftId
* @param quantity
* @return
*/
public boolean decreaseGiftStock(Long giftId, int quantity) {
String key = getActivityAwardStockKey(giftId);
//LUA脚本保证原子性
Long update = stringRedisTemplate.execute(stockScript, Collections.singletonList(key), String.valueOf(quantity));
logger.info("活动-兑换礼品, giftId:{} 减库存quantity:{} 后的结果:{}",
giftId, quantity, update);
return update >= 0;
}
private String getActivityAwardStockKey(Long giftId) {
return String.format("%s:%s", "stock", giftId);
}
}
GiftService 扣减用户可用积分代码如下:
@Transactional(rollbackFor = Exception.class)
public ApiResult<Long> saveUserGift(UserPoint userPoint, int requiredPoint, ActivityUserGift record) {
Long id = userPoint.getId();
//1.扣减用户可用积分
int update = userPointMapper.updateUserAvailablePoint(id, requiredPoint);
if (update<1) {
throw new UserPointShortageException("可用积分不足");
}
//2.插入兑换礼品记录
activityUserGiftMapper.insert(record);
return ApiResult.buildSuccessResult(record.getId().longValue());
}
public ActivityGift getGiftById(Integer activityId, Long giftId) {
return activityGiftMapper.findGiftById(giftId);
}
public ActivityUserGift createOrder(Integer activityId, Long userId, ActivityGift activityGift, int quantity) {
ActivityUserGift userGift = new ActivityUserGift();
//赋值
return userGift;
}
其中,扣减用户可用积分SQL如下:
<update id="updateUserAvailablePoint">
update activity_user_point
set available_point = available_point - #{requiredPoint}
where id=#{id} and available_point >=#{requiredPoint};
</update>
local investment_key = KEYS[1]
local point_key = KEYS[2]
local investmentAmount = tonumber(ARGV[1])
local pointUnit = tonumber(ARGV[2])
local totalInvestmentAmount = tonumber(redis.call("INCRBY", investment_key, investmentAmount))
local totalPoints = math.floor(totalInvestmentAmount / pointUnit);
redis.call("SET", point_key, totalPoints)
return {totalInvestmentAmount, totalPoints}
stock_decr.lua
local stocks_key = KEYS[1]
local acquiredNum = tonumber(ARGV[1])
local current = tonumber(redis.call("GET", stocks_key))
if current == nil then
current = 0
end
local success = -1;
if current >= acquiredNum then
success = tonumber(redis.call("DECRBY", stocks_key, acquiredNum))
end
return success
The text was updated successfully, but these errors were encountered:
场景
活动期间,用户投资指定理财产品计划每满XX元(例如每满1000元),兑换积分加1,用户可以使用兑换积分去兑换礼品。
1.投资得兑换积分
注:需要把不足1000的投资记录下来,比如两次分别投资1500元,第一次得1个兑换积分,第二次得2个兑换积分,一共3个兑换积分。
2.兑换积分换礼品
实物、虚拟卡、红包 多种类型的礼品,全都平铺在页面上。实物和虚拟卡礼品有总数限制
已兑完的礼品,按钮为“抢光啦”,不可点击。
设计思路
计算用户兑换积分
用户兑换礼品
兑换礼品主逻辑如下:
GiftService 库存相关代码如下:
GiftService 扣减用户可用积分代码如下:
其中,扣减用户可用积分SQL如下:
activity_user_point表DDL如下:
其中,available_point为 bigint(20) unsigned 可以在数据库层面保证 available_point小于0情况发生。
附录 - Lua脚本
1、investment_point.lua
The text was updated successfully, but these errors were encountered: