1. 程式人生 > >redis分散式鎖的設計和使用demo

redis分散式鎖的設計和使用demo

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;

 

}