redis setnx 防重复提交“不生效”
setnx广泛用于防重复提交、超时重试的场景来保证幂等。
主要利用setnx特性,设置一个特定的key和一个合适的过期时间,成功则执行业务逻辑。执行完毕会在finally代码块中删掉此key,防止抛出异常的情况长时间持有此redis锁。
用法还是很简单的,但一些同学还会粗心的犯错,这也是code review中特别要注意的点。
问题代码
public void test() {
try {
if (!redis.setnx(key, 5)) {
return resultError("访问频繁,请稍后重试");
}
//业务代码...
} finally {
redis.del(key);
}
}
分析
并发情况下达不到预期效果,如:
- 线程一执行setnx成功,正在执行业务代码
- 线程二执行setnx失败,接着执行了finally代码块,把锁删掉了
- 线程三此时再去执行setnx时就会成功
解决
setnx应放在try外层
public void test() {
if (!redis.setnx(key, 5)) {
return resultError("访问频繁,请稍后重试");
}
try {
//业务代码...
} finally {
redis.del(key);
}
}