redis的setNX [SET if Not Exists] 方法,可以利用它来实现锁的效果
场景一: 防重复提交
实现思路: 提交方法开始设置setNX,返回1,成功,设置过期时间,继续执行方法,最后删除锁; 返回0,return
代码示例
// 防止重复提交
Long flag=RedisUtil.setNX("withdrawLock_"+saveBean.getUserId(),"1");
if(flag!=1L){
if(flag==2L){
logger.error("withdrawLock_"+saveBean.getUserId()+" Redis操作失败");
return false;
}
logger.error(saveBean.getUserId() + "提现重复提交,已拒绝!");
return false;
}
try {
// 60秒过期
RedisUtil.setString("withdrawLock_"+saveBean.getUserId(),"1",60);
} catch (Exception e) {
logger.error(ExceptionHelper.getExceptionDetail(e));
return false;
} finally {
RedisUtil.removeKey("withdrawLock_"+saveBean.getUserId());
}
场景二: 加锁,形成队列
实现思路: 提交方法开始设置setNX,返回1,成功,设置过期时间,继续执行方法,最后删除锁; 返回0,休眠一秒(比如),设置setNX,返回1,如上;返回0,继续,这样循环15次(比如),即等待15秒,还是返回0,则return false,操作失败。
代码示例
int times=0;
Long flag=RedisUtil.setNX("accountLock"+bean.getUserId(),"1");
while(flag!=1L){
if(flag==2L){
logger.error("accountLock"+bean.getUserId()+" Redis操作失败");
break;
}
try {
Thread.sleep(1000);
times++;
if(times>15){
logger.error(bean.getUserId() + "更新账户数据已等待15秒,更新失败!");
return false;
}
} catch (InterruptedException e) {
logger.error(bean.getUserId() + "等待更新账户数据线程中断!");
return false;
}
flag=RedisUtil.setNX("accountLock"+bean.getUserId(),"1");
}
try {
// 60秒过期
RedisUtil.setString("accountLock"+bean.getUserId(),"1",60);
//逻辑代码
} catch (AccountException ae) {
} finally {
RedisUtil.removeKey("accountLock"+bean.getUserId());
}
二者区别在于,设置setNX失败后,一个立即返回,不再执行; 另一个则选择等待.