redis实现分布式锁

什么是分布式锁,什么是分布式,通俗来讲,分布式,就是应用部署了不止一个地方,可以是垂直分布式也可以是水平分布式,垂直就是部署在同一个物理机上,水平就是分布在不同的物理机上,为什么要用到分布式锁,以前我们学习的java里就可以用锁,比如使用synchronized关键字,对于单个应用,没问题的,随着服务器压力增加,应用部署会不止一个,每个应用里都运行相同的一套后台代码,假设有server_A和server_B,用户A和用户B,此时用户A访问server_A同时用户B访问server_B,server_A和server_B相互独立存在,就会导致资源同时被多个请求占用,假设sever_A和server_B里的业务是访问一次累加1,这样就会导致数据出现问题,用户A和用户B的两次请求可能结果只加了1次,如何解决呢,这里就用到分布式锁,分布式锁保证了多个用户不管同时分别访问不同server_A或者server_B等更多的服务应用,都需要先去同一个地方验证身份,这里用到redis来作为验证身份的地方。

直接上干货。

1、redis工具类

import java.util.Collections;

import redis.clients.jedis.Jedis;

public class RedisTool {
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 Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTime 超期时间
* @return 是否获取成功
*/
public static boolean getRedisLock(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;

/**
* 释放分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @return 是否释放成功
*/
public static boolean releaseRedisLock(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;

}
}

2、redis服务层定义两个方法,代码如下:

//redis 分布式锁 获取锁
public boolean getRedisLock(String lockKey, String requestId, int expireTime){
Jedis jedis=null;
Boolean result=false;
try {
jedis=jedisPool.getResource();
result=RedisTool.getRedisLock(jedis, lockKey, requestId, expireTime);
} catch (RuntimeException e) {
e.printStackTrace();
if(jedis!=null) {
jedisPool.returnBrokenResource(jedis);//获取连接失败时,应该返回给pool,
}
}
finally{
// 正确释放资源
if(jedis != null ) {
jedisPool.returnResource(jedis);
}
}
return result;

}
//redis 分布式锁 解锁
public boolean releaseRedisLock(String lockKey, String requestId){
Jedis jedis=null;
Boolean result=false;
try {
jedis=jedisPool.getResource();
result=RedisTool.releaseRedisLock(jedis, lockKey, requestId);
} catch (RuntimeException e) {
e.printStackTrace();
if(jedis!=null) {
jedisPool.returnBrokenResource(jedis);//获取连接失败时,应该返回给pool,
}
}
finally{
// 正确释放资源
if(jedis != null ) {
jedisPool.returnResource(jedis);
}
}
return result;
}

redis服务层用到 redis.clients.jedis.Jedis;  redis.clients.jedis.JedisPool;这两个类

业务层对资源上锁直接调用 redis服务层的getRedisLock方法,返回true表示拿到锁成功,上锁业务处理完成后记得要调用releaseRedisLock方法释放锁,返回false表示该资源被别的请求拿到锁,正在使用中。调用redis服务层的releaseRedisLock方法可以释放当前锁

redis服务层的两个方法说明:

getRedisLock(String lockKey, String requestId, int expireTime),lockKey可以设置上锁资源的唯一表示,比如订单编号,requestId可以设置请求标识,比如用户的id等可以标识请求者的标识,主要用来释放锁,类似于map里的key,唯一,expireTime为失效时间,多久之后自动释放锁,单位毫秒。

releaseRedisLock(String lockKey, String requestId),lockKey、requestId同上。


推荐 收藏
评论(0) 阅读(432)
刷新评论 返回顶部
JiFeng最新博客