線上接口有同使用者請求的并發問題,是以準備用setnx做一個鎖
為什麼要用setnx:因為 Redis Setnx(SET if Not eXists) 指令是在指定的 key 不存在時,為 key 設定指定的值,是以setnx是redis的一個原子性指令
實作思路:根據使用者資訊生成一個key,放緩存待 接口執行完畢之後,删除該緩存,下次同使用者請求進來,如果未執行完畢則緩存還存在,放緩存失敗則傳回對應提示資訊,接口停止繼續執行
上代碼:
@Autowired(required = false)
private Pool<Jedis> poolJedis;
/**
* 添加鎖 防并發 此方法添加鎖未設定過期時間,需手動釋放
*
* @param key key
* @param seconds 緩存過期時間
* @return boolean
*/
public boolean tryLock(String key,int seconds) {
if (Validator.isNullOrEmpty(poolJedis)) {
return false;
}
try (Jedis jedisCluster = poolJedis.getResource()) {
// 在指定的 key 不存在時,為 key 設定指定的值。
// 根據以下第三個nxxx參數,把key、value set到redis中
// NX : not exists, 隻有key 不存在時才把key value set 到redis
// XX : is exists, 隻有key 存在時才把key value set 到redis
// 第四個expx參數有兩個值可選 :
// EX : seconds 秒
// PX : milliseconds 毫秒
String nx = jedisCluster.set(key, "value", "NX", "EX", seconds);
if (Validator.isNotNullOrEmpty(nx) && "OK".equals(nx)) {
return true;
}
} catch (Exception e) {
LOGGER.error("addLock error:", e);
}
return false;
}
/**
* 釋放鎖
*
* @param key key
*/
public void clearLock(String key) {
Jedis jedisCluster = null;
try {
jedisCluster = pool.getResource();
Long a = jedisCluster .del(key);
} catch (Exception e) {
LOGGER.error("", e);
//線程休眠1秒
try {
Thread.sleep(1000);
removeLock(key);
} catch (InterruptedException e1) {
LOGGER.error("removeLock error:", e1);
Thread.currentThread().interrupt();
} finally {
if (jedisCluster != null) {
jedisCluster .close();
}
}
}
}