Redis implements distributed locks (two)

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{
 // 获取锁失败
}

 

Guess you like

Origin blog.csdn.net/qq_38428623/article/details/105495503