1. 配置和依赖
# build.gralde 添加依赖
implementation 'org.springframework.boot:spring-boot-starter-data-redis:2.1.5.RELEASE'
# application.xml 添加 redis 端口配置
spring:
redis:
cluster:
nodes:
- xxxx:6379
- yyyy:6379
2. Redis 配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
3. 加锁和解锁的实现
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class RedisService {
private static final String REDIS_UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 获取分布式锁
*
* @param key
* @param token
* @param expireInSeconds 锁超时时间
* @return
*/
public boolean tryLock(String key, String token, long expireInSeconds) {
Boolean res = redisTemplate.opsForValue().setIfAbsent(key, token, expireInSeconds, TimeUnit.SECONDS);
return Objects.equals(res, true);
}
/**
* 分布式锁unlock,使用lua脚本保证事务
*
* @param key
* @param token lock时的token值,只有token一致才能解锁
* @return
*/
public void unlock(String key, String token) {
try {
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(REDIS_UNLOCK_SCRIPT, Long.class);
Long res = redisTemplate.execute(redisScript, Collections.singletonList(key), token);
if (!Objects.equals(res, 1L)) {
log.warn("redis unlock wrong:key=[{}],token=[{}],res=[{}]", key, token, res);
}
} catch (Exception e) {
log.error("redis unlock error:key=[{}],token=[{}]", key, token, e);
}
}
加锁添加等待时间
public boolean tryAcquireLock(String key, String token, long lockTimeout, long acquireTimeout) {
try {
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end) {
Boolean res = redisTemplate.opsForValue().setIfAbsent(key, token, lockTimeout, TimeUnit.MILLISECONDS);
if (Boolean.TRUE.equals(res)) {
return true;
}
try {
Thread.sleep(100);
} catch (Exception e) {
log.error("thread sleep error", e);
Thread.currentThread().interrupt();
}
}
} catch (Exception e) {
log.error("try acquire lock error, ", e);
}
return false;
}