本文主要基于Springboot2.x,基于lettuce客户端实现
组件依赖
Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<!--如果需要使用Redis线程池,需要依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version>
</dependency>
配置
spring:
redis:
timeout: 5000ms
host: 192.168.1.123
password: 1password1
database: 1
lettuce:
pool:
max-idle: 8
min-idle: 1
max-wait: 3000ms
max-active: 8
代码实现
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class RedisLock {
@Resource
private RedisTemplate redisTemplate;
public static final String UNLOCK_LUA;
/**
* 释放锁脚本,原子操作
*/
static {
StringBuilder sb = new StringBuilder();
sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
sb.append("then ");
sb.append(" return redis.call(\"del\",KEYS[1]) ");
sb.append("else ");
sb.append(" return 0 ");
sb.append("end ");
UNLOCK_LUA = sb.toString();
}
/**
* 获取分布式锁,锁对象、以及设置过期时间应该为原子操作
* @param lockKey
* @param requestId 唯一ID, 可以使用UUID.randomUUID().toString();
* @param expire
* @param timeUnit
* @return
*/
public boolean tryLock(String lockKey, String requestId, long expire, TimeUnit timeUnit) {
try{
RedisCallback<Boolean> callback = (connection) -> {
return connection.set(lockKey.getBytes(Charset.forName("UTF-8")), requestId.getBytes(Charset.forName("UTF-8")), Expiration.seconds(timeUnit.toSeconds(expire)), RedisStringCommands.SetOption.SET_IF_ABSENT);
};
return (Boolean)redisTemplate.execute(callback);
} catch (Exception e) {
log.error("redis lock error.", e);
}
return false;
}
/**
* 释放锁。传入requestId,只能释放自己线程加的锁
* @param lockKey
* @param requestId 唯一ID, 可以使用UUID
* @return
*/
public boolean releaseLock(String lockKey, String requestId) {
RedisCallback<Boolean> callback = (connection) -> {
return connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN ,1, lockKey.getBytes(Charset.forName("UTF-8")), requestId.getBytes(Charset.forName("UTF-8")));
};
return (Boolean)redisTemplate.execute(callback);
}
/**
* 获取Redis锁的value值
* @param lockKey
* @return
*/
public String get(String lockKey) {
try {
RedisCallback<String> callback = (connection) -> {
return new String(connection.get(lockKey.getBytes()), Charset.forName("UTF-8"));
};
return (String)redisTemplate.execute(callback);
} catch (Exception e) {
log.error("get redis occurred an exception", e);
}
return null;
}
}
使用
@Autowired
RedisLock redisLock;
@Test
public void testLock() {
String redisKey = "testLock";
String requestId = "123456";
boolean result = redisLock.tryLock(redisKey, requestId, 60, TimeUnit.SECONDS);
System.out.println("lock:" + result);
System.out.println("release lock:" + redisLock.releaseLock(redisKey, requestId));
}
版权声明:本文为xiehd313原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。