线上接口有同用户请求的并发问题,所以准备用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 ((poolJedis)) {
return false;
}
try (Jedis jedisCluster = ()) {
// 在指定的 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 = (key, "value", "NX", "EX", seconds);
if ((nx) && "OK".equals(nx)) {
return true;
}
} catch (Exception e) {
("addLock error:", e);
}
return false;
}
/**
* 释放锁
*
* @param key key
*/
public void clearLock(String key) {
Jedis jedisCluster = null;
try {
jedisCluster = ();
Long a = jedisCluster .del(key);
} catch (Exception e) {
("", e);
//线程休眠1秒
try {
(1000);
removeLock(key);
} catch (InterruptedException e1) {
("removeLock error:", e1);
().interrupt();
} finally {
if (jedisCluster != null) {
jedisCluster .close();
}
}
}
}