一、前景信息
基于像双十一大促销这样的活动,用户参与量极剧增加,当很多用户参与一项活动时,比如抽奖场景,这种场景下,当数据库中有一条记录专门记录库存时,如果是通过锁这一条记录更新库存时,就会出现大量的用户在应用获得数据库的连接后,等待前一个用户更新完库表释放锁,才进入再扣减库存,这样就会有很多用户处于等待状态,而等待的用户是持久数据库连接的,这个资源非常宝贵,占用后,其他请求进不来,最终导致一个请求需要几分钟来响应。所以这种情况一般都是使用redis缓存来处理库存,只要保证没有出现超卖的情况。这里通过 Redisson 延迟队列的 + 定时任务的方式,缓慢消耗队列数据来更新库表数据变化。
二、流程实现
2.1 缓存奖品库存
public boolean assembleLotteryStrategy(Long strategyId) {
// 1. 查询策略配置
List<StrategyAwardEntity> strategyAwardEntities = repository.queryStrategyAwardList(strategyId);
/* 2 缓存奖品库存 */
for (StrategyAwardEntity strategyAward : strategyAwardEntities) {
Integer awardId = strategyAward.getAwardId();
Integer awardCount = strategyAward.getAwardCount();
cacheStrategyAwardCount(strategyId, awardId, awardCount);
}
}
/**
* 缓存奖品库存到Redis
*
* @param strategyId 策略ID
* @param awardId 奖品ID
* @param awardCount 奖品库存
*/
private void cacheStrategyAwardCount(Long strategyId, Integer awardId, Integer awardCount) {
String cacheKey = Constants.RedisKey.STRATEGY_AWARD_COUNT_KEY + strategyId + Constants.UNDERLINE + awardId;
repository.cacheStrategyAwardCount(cacheKey, awardCount);
}
public void cacheStrategyAwardCount(String cacheKey, Integer awardCount) {
if (redisService.isExists(cacheKey)) return;
redisService.setAtomicLong(cacheKey, awardCount);
}
public void setAtomicLong(String key, long value) {
redissonClient.getAtomicLong(key).set(value);
}
在Domain层这里增加了缓存奖品库存数据的操作,最终会调用仓储层,向缓存写入数据。
StrategyRepository中的cacheStrategyAwardCount方法 redissonClient.getAtomicLong(key).set(value);