库存问题"/>
redis rua解决库存问题
项目总结59:Redis分布式锁解决电商订单库存并发问题
在电商分布式项目中,需要考虑提交订单时,因为并发的原因导致库存异常的情况。
其中一个解决方案是:使用redis锁,因为Redis是单线程的,即线程安全的;在提交订单的时候,先通过Redis锁进行库存判断,如果库存校验通过,则正常提交顶顶那,否则返回失败。
具体逻辑如下:
1- 用户请求提交订单接口,接口内先通过Redis锁进行库存校验(如果第一次获取锁失败,则会继续请求锁,但不超过5次);
2- Redis锁进行库存校验,从订单层面具有排他性(即一个订单在进行Redis锁库存校验时),其它提交的订单只能等待。
3- 且Redis锁进行库存校验,做两件事:(1)进行Redis库存校验,如果库存不够,则返回false;否则继续(2);(2)进行Redis减库存操作。
4-Redis锁进行库存校验通过后,订单信息被正常提交。
具体代码如下
@AutowiredprivateCommonRedisHelper commonRedisHelper;public final static String PREFIX_LOCK_ORDER_SUBMIT = "lock_orderSubmit";//校验并更新库存
public Boolean updateStockToRedis(ListcartIdList){boolean lock =commonRedisHelper.lock(PREFIX_LOCK_ORDER_SUBMIT);if(lock){//更新redis中sku的库存//代码略... reduceMultiSkuStock(cartIdList)//删除锁
commonRedisHelper.delete(PREFIX_LOCK_ORDER_SUBMIT);return true;
}else{//设置失败次数计数器, 当到达5次时, 返回失败
int failCount = 1;while(failCount <= 5){//等待100ms重试
try{
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}if(commonRedisHelper.lock(PREFIX_LOCK_ORDER_SUBMIT)){//执行逻辑操作//更新redis中sku的库存//代码略... reduceMultiSkuStock(cartIdList)//删除锁
commonRedisHelper.delete(PREFIX_LOCK_ORDER_SUBMIT);return true;
}else{
failCount++;
}
}return false;
}
}//判断并更新某个SKU库存
private boolean reduceMultiSkuStock(ListcartIdList){//2-判断秒杀商品SKU是否足够//代码略...//2-更新秒杀商品的库存//代码略...
}
CommonRedisHelper 类
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisCallback;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.stereotype.Component;importjava.util.Objects;
@Componentpublic classCommonRedisHelper {//锁名称
public static final String LOCK_PREFIX = "redis_lock";//加锁失效时间,毫秒
public static final int LOCK_EXPIRE = 300; //ms
@Autowired
RedisTemplate redisTemplate;/*** 最终加强分布式锁
*
*@paramkey key值
*@return是否获取到*/
public booleanlock(String key){
String lock= LOCK_PREFIX +key;//利用lambda表达式
return (Boolean) redisTemplate.execute((RedisCallback) connection ->{//当前锁的过期时间
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;//当锁不存在时,设置锁,key为锁名称,value为过期时间
Boolean acquire =connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());if(acquire) {//如果设置成功,则返回true
return true;
}else{//如果锁没有设置成功//获取已经存在的锁的value(即已经存在的锁的过期时间)
byte[] value =connection.get(lock.getBytes());//当已经存在的旧锁的过期时间存在时
if (Objects.nonNull(value) && value.length > 0) {long expireTime = Long.parseLong(newString(value));//如果旧锁已经过期,则重新加锁
if (expireTime
byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());//判断:如果旧锁已经过期,则返回true,否则返回false
return Long.parseLong(new String(oldValue))
}
}
}return false;
});
}/*** 删除锁
*
*@paramkey*/
public voiddelete(String key) {
String lock= LOCK_PREFIX +key;
redisTemplate.delete(lock);
}
}
更多推荐
redis rua解决库存问题
发布评论