分布式锁 要解决的问题就是高并发时导致的数据重复读取。
为了保证数据的 一致性,在单服务中我们使用 synchronize 在分布式服务中,这个显然是不行的,为了解决这个问题,我们一般使用 Redis的分布式锁 或 ZooKeeper的分布式锁。
直接上代码:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
public class RedisUtils {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
/**
* 尝试获取分布式锁
*
* @param jedis Jedis对象
* @param lockKey 锁key
* @param requestId 用来标识 谁加的锁。解锁的时候也需要传过去
* @param expireTime 过期期时间
* @return 是否获取成功
*/
public static synchronized boolean lock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
private static final Long RELEASE_SUCCESS = 1L;
/**
* 解锁 通过 lua 执行可以保证原子性,确保判断 解锁 的中间时候,锁过期,导致误解别人锁的情况。
*
* @param jedis Jedis对象
* @param lockKey 锁key
* @param requestId 用来标识 谁加的锁
* @return 是否释放成功
*/
public static boolean unLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}