package com.nchu.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Component
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 加锁
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key, String value) {
//setIfAbsent 可以设置key和value 则返回true 否则返回false key是商品id value值为当前时间+超时时间
if(redisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
//如果锁过期
if (!StringUtils.isEmpty(currentValue)
&& Long.parseLong(currentValue) < System.currentTimeMillis()) {
//获取上一个锁的时间 并把当前最新的时间+超时时间放进去
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
//最后再判断一次 这期间没有人去加过锁 因为当锁过期的时候很可能进去多个线程执行到这 这个时候的时间还是之前取到的时间 说明自己加锁成功
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
return true;
}
}
return false;
}
/**
* 解锁
* @param key
* @param value
*/
public void unlock(String key, String value) {
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e) {
log.error("【redis分布式锁】解锁异常, {}", e);
}
}
}
使用
/**
* 用户付款时候减去库存
*/
private int subStock(String OrderId) {
List<OrderDetail> orderDetailList = orderDetailMapper.selectByOrderId(OrderId);
List<String> ProductIds = orderDetailList.stream().map(x -> x.getProductId()).collect(Collectors.toList());
Map<String, OrderDetail> productIdAndOrderDetail = new HashMap<>();
orderDetailList.forEach(x -> productIdAndOrderDetail.put(x.getProductId(), x));
for (String id : ProductIds) {
// 分布式锁 加锁
Long currentDate = System.currentTimeMillis() + 5000; //设置加锁时间
Boolean result = redisLock.lock(id, currentDate.toString());
//不成功重试
while (!result) {
currentDate = System.currentTimeMillis() + 5000; //设置加锁时间
result = redisLock.lock(id, currentDate.toString());
}
ProductInfo productInfo = productInfoMapperEx.selectByPrimaryKey(id);
OrderDetail orderDetail=productIdAndOrderDetail.get(id);
Integer nowStockNum = productInfo.getProductStock() - orderDetail.getProductQuantity();
if (nowStockNum <= 0) { //小于0 说明库存不足
return -1;
}
productInfo.setProductStock(nowStockNum);
//更新库存
productInfoMapperEx.updateByPrimaryKey(productInfo);
//解锁
redisLock.unlock(id, currentDate.toString());
}
return 1;
}