背景
在高并发的系统中,并发的操作会导致数据重复插入,或者资源竞争。需要做一个分布式锁,保证业务数据的一致性。
关注点
- 设置redis必须是,key 不存在再设置值
- 失效的redis的时候,需要比较失效的数据是原来塞进去的数据
代码实现
分布式锁核心实现类
package com.nelson.spring.hello.world.service.lock;
import com.nelson.spring.hello.world.service.cache.ReidsClient;
import lombok.extern.slf4j.Slf4j;
/**
* Redis分布式的锁
* <p>
* 1. 使用redis实现分布式锁
*
* @author bingbing.xbb
* @Date 2021-01-29
*/
@Slf4j
public class RedisDistributedLock {
ReidsClient reidsClient;
/**
* 获取锁
* 说明:1. 设置超时时间防止异常锁死
*
* @param key
* @param value
* @param expireTime
* @return
*/
public boolean tryGetLock(String key, String value, int expireTime) {
try {
String result = reidsClient.set(key, value, "nx", "nx", expireTime);
if ("SUCCESS".equals(result)) {
return true;
}
} catch (Exception e) {
log.error("tryGetLock exception", e);
}
return false;
}
/**
* 释放锁
* 说明:1. key-value 必须一致才能释放锁
*/
public boolean releaseLock(String key, String value) {
try {
String cad = reidsClient.cad(key, value);
if ("SUCCESS".equals(cad)) {
return true;
}
} catch (Exception e) {
log.error("releaseLock exception", e);
}
return false;
}
public static void main(String[] args) {
RedisDistributedLock redisDistributedLock = new RedisDistributedLock();
String key = "key";
String value = "value";
/**
* 尝试获取锁
* 说明:
* 1. 尝试5次,每次等待10ms
* 2. 最后释放锁
*/
int tryCount = 0;
try {
while (tryCount++ <= 5) {
boolean b = redisDistributedLock.tryGetLock(key, value, 20);
if (b) {
// do something
log.info("lock success");
} else {
Thread.sleep(10);
}
}
} catch (Exception e) {
log.info("do something exception", e);
} finally {
redisDistributedLock.releaseLock(key, value);
}
if (tryCount > 5) {
throw new RuntimeException("get lock timeout.change the wait time");
}
}
}
Redis的接口方法定义
package com.nelson.spring.hello.world.service.cache;
/**
* @author nelson
*/
public interface ReidsClient {
/**
* 放入redis缓存
* 说明:
*
* @param key
* @param value
* @param expireTime
* @param expx ex:设置键的过期时间为 second 秒 px:设置键的过期时间为 millisecond 毫秒
* @param nxxx nx:只在键不存在时 xx:只在键已经存在时
* @return
*/
String set(String key, String value, String nxxx, String expx, int expireTime);
/**
* 当oldvalue和key的value相等时,删除该key;不相等则无效
*
* @param key
* @param value
* @return
*/
String cad(String key, String value);
}