1. Dependent package
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
2. Distributed lock
import com.zto.ztrace.util.RedisStringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisLock {
/**
* redis操作的类
*/
@Autowired
private RedisStringUtil redisStringUtil;
/**
* 加锁的值
*/
private static final String LOCK_VALUE = "TRUE";
/**
* 默认超时时间 3000ms
*/
private static final int TIME = 3000;
/**
* 锁的前缀,命名空间
*/
private static final String PREFIX = "LOCKS:";
/**
* 加锁
*
* @param key 键
* @return 返回是否允许执行
*/
public boolean lock(final String key) {
return this.redisStringUtil.setIfNotExists(RedisLock.PREFIX.concat(key), RedisLock.LOCK_VALUE, RedisLock.TIME);
}
/**
* 加锁,有超时时间(建议) 避免解锁失败导致死锁
*
* @param key 键
* @param expireMilliSeconds 超时时间(默认 耗秒)
* @return 返回是否允许执行
*/
public boolean lock(final String key, final long expireMilliSeconds) {
return this.redisStringUtil.setIfNotExists(RedisLock.PREFIX.concat(key), RedisLock.LOCK_VALUE, expireMilliSeconds);
}
/**
* 加锁,有超时时间(建议) 避免解锁失败导致死锁
*
* @param key 键
* @param time 超时时间
* @param unit 超时单位
* @return 返回是否允许执行
*/
public boolean lock(final String key, final long time, final TimeUnit unit) {
return this.redisStringUtil.setIfNotExists(RedisLock.PREFIX.concat(key), RedisLock.LOCK_VALUE, time, unit);
}
/**
* 解锁 this.redisStringUtil.set(PREFIX.concat(key), LOCK_VALUE, 5, TimeUnit.MILLISECONDS);
*
* @param key 键
*/
public void unlock(final String key) {
this.redisStringUtil.delete(RedisLock.PREFIX.concat(key));
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisStringUtil {
/**
* 注入Redis字符串模板
*/
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 设置值
*
* @param key 键
* @param value 值
*/
public void set(final String key, final String value) {
this.redisTemplate.opsForValue().set(key, value);
}
/**
* 当前的值 + 1
*
* @param key 键
* @return 返回操作之后的值
*/
public Long increment(final String key) {
return this.redisTemplate.opsForValue().increment(key, 1);
}
/**
* 当前的值加 + value
*
* @param key 键
* @param value 值
* @return 返回操作之后的值
*/
public Long incrementBy(final String key, final long value) {
return this.redisTemplate.opsForValue().increment(key, value);
}
/**
* 当前的值 - 1
*
* @param key 键
* @return 返回操作之后的值
*/
public Long descend(final String key) {
return this.redisTemplate.opsForValue().increment(key, -1);
}
/**
* 当前的值 - value
*
* @param key 键
* @return 返回操作之后的值
*/
public Long descendBy(final String key, final long value) {
return this.redisTemplate.opsForValue().increment(key, -Math.abs(value));
}
/**
* 设置值
*
* @param key 键
* @param value 值
* @param timeout 超时(秒)
*/
public void set(final String key, final String value, final long timeout) {
this.redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 设置值
*
* @param key 键
* @param value 值
* @param timeout 超时时间
* @param timeout 超时时间单位
*/
public void set(final String key, final String value, final long timeout, final TimeUnit timeUnit) {
this.redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 获取值
*
* @param key 键
* @return 获取值
*/
public String get(final String key) {
return this.redisTemplate.opsForValue().get(key);
}
/**
* 删除
*
* @param key 健
*/
public void delete(final String key) {
this.redisTemplate.delete(key);
}
/**
* 当不存在的时候设置值,
*
* @param key 键
* @param value 值
* @param expireMilliSeconds 超时时间(单位 毫秒)
* @return 成功 返回 OK
*/
public boolean setIfNotExists(final String key, final String value, final long expireMilliSeconds) {
return this.setIfNotExists(key, value, expireMilliSeconds, TimeUnit.MILLISECONDS);
}
/**
* 当不存在的时候设置值,
*
* @param key 键
* @param value 值
* @param expire 超时时间
* @param timeUnit 超时单位
* @return 成功 返回 OK
*/
public boolean setIfNotExists(final String key, final String value, final long expire, final TimeUnit timeUnit) {
return this.redisTemplate.opsForValue().setIfAbsent(key, value, expire, timeUnit);
}
}
3. How to use
import com.zto.ztrace.extend.RedisLock;
@Autowired
private RedisLock redisLock;
if (this.redisLock.lock(key)) {
try {
// 业务逻辑
} finally {
this.redisLock.unlock(key);
}
}else{
// 获取锁失败
}