分布式锁的实现工具类

Posted 格子衫111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式锁的实现工具类相关的知识,希望对你有一定的参考价值。

分布式锁一般使用缓存实现的,下面提供一个工具类,

1、缓存配置:

bootstrap.yml 或者 application.properties:

spring.redis.cluster.nodes: x.x.x.x:6379
spring.cache.redis.timeToLive: 360

2、添加pom依赖:

		 <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.17</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

<!--        引入redisTemplate-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.7.0</version>
        </dependency>

3、辅助工具类:

ErrorInfoEnum.java

/**
 * 系统及业务级别的通用错误码
 */
public enum ErrorInfoEnum  
  //成功
  SUCCESS("0", "success"),
	
  ORDER_RESERVATION_GET_LOCK_ERROR("-110","加锁失败"),
  
  //失败
  FAILED("-1", "system exception");

  private String code;

  private String message;

  ErrorInfoEnum(String code, String message) 
    this.code = code;
    this.message = message;
  

  public String getCode() 
    return code;
  

  public void setCode(String code) 
    this.code = code;
  

  public String getMessage() 
    return message;
  

  public void setMessage(String message) 
    this.message = message;
  

  @Override
  public String toString() 
    return "ErrorInfoEnum" +
        "code='" + code + '\\'' +
        ", message='" + message + '\\'' +
        '';
  

ReqBody.java

/**
 * 请求体
 * @param <T>
 */
public final class ReqBody<T> 

  private static final long serialVersionUID = 1L;

  // 调用方应用名称
  protected String appName;

  // 数据来源
  protected String source;

  // 加密签名
  private String sign;

  //时间戳
  private String timestamp;

  //参数体
  protected T param;

  public String getAppName() 
    return appName;
  

  public void setAppName(String appName) 
    this.appName = appName;
  

  public String getSource() 
    return source;
  

  public void setSource(String source) 
    this.source = source;
  

  public String getSign() 
    return sign;
  

  public void setSign(String sign) 
    this.sign = sign;
  

  public String getTimestamp() 
    return timestamp;
  

  public void setTimestamp(String timestamp) 
    this.timestamp = timestamp;
  

  public T getParam() 
    return param;
  

  public void setParam(T param) 
    this.param = param;
  

  @Override
  public String toString() 
    return "ReqBody" +
        "appName='" + appName + '\\'' +
        ", source='" + source + '\\'' +
        ", sign='" + sign + '\\'' +
        ", timestamp='" + timestamp + '\\'' +
        ", param=" + param +
        '';
  

RespBody.java

/**
 * 返回体
 */
public final class RespBody<T> implements Serializable 

  private static final long serialVersionUID = -3455864552409084052L;

  /**
   * 响应代码
   */
  private String code;

  /**
   * 响应消息
   */
  private String message;

  /**
   * 响应结果
   */
  private transient T result;

  public RespBody() 
    successParam();
  

  public RespBody(T result) 
    successParam();
    this.result = result;
  

  public void setIErrorInfo(ErrorInfoEnum errorInfo) 
    this.code = errorInfo.getCode();
    this.message = errorInfo.getMessage();
  

  private void successParam() 
    this.code = ErrorInfoEnum.SUCCESS.getCode();
    this.message = ErrorInfoEnum.SUCCESS.getMessage();
  

4、缓存工具类:

import com.alibaba.fastjson2.JSONObject;
import com.zwt.common.ReqBody;
import com.zwt.common.RespBody;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RedisTemplateService 
	private Logger log = LoggerFactory.getLogger(RedisTemplateService.class);
	@Autowired
	private RedisTemplate redisTemplate;

	public RespBody<String> getRedisObjectByKey(ReqBody<String> reqBody) 
		String result = null;
		if (!StringUtils.isEmpty(reqBody.getParam())) 

			Object lightObject = redisTemplate.opsForValue().get(reqBody.getParam());
			result = JSONObject.toJSONString(lightObject);
		
		return new RespBody<>(result);
	

	public RespBody<String> getRedisListByKey(ReqBody<String> reqBody) 

		String result = null;
		if (!StringUtils.isEmpty(reqBody.getParam())) 

			Object lightObject = redisTemplate.opsForList().range(reqBody.getParam(), 0, -1);
			result = JSONObject.toJSONString(lightObject);
		
		return new RespBody<>(result);
	

	public RespBody<Object> setRedisObjectByKey(ReqBody<List<String>> reqBody) 

		redisTemplate.opsForValue().set(reqBody.getParam().get(0), reqBody.getParam().get(1),
				Integer.parseInt(reqBody.getParam().get(2)), TimeUnit.MINUTES);
		return new RespBody<>();
	

	public RespBody<Object> setRedisListByKey(ReqBody<List<String>> reqBody) 

		Object ob = redisTemplate.opsForList().rightPush(reqBody.getParam().get(0), reqBody.getParam().get(1));

		return new RespBody<>(ob);
	

	public RespBody<Object> deleteRedisObjectByKey(ReqBody<String> reqBody) 

		// 删除redis的值
		redisTemplate.opsForValue().set(reqBody.getParam(), 1, 1, TimeUnit.MILLISECONDS);
		return new RespBody<>();
	

	public RespBody<Object> deleteRedisListByKey(ReqBody<List<String>> reqBody) 

		// 删除redis的值
		redisTemplate.opsForList().remove(reqBody.getParam().get(0), 0, reqBody.getParam().get(1));
		return new RespBody<>();
	

	/**
	 * 加分布式锁
	 *
	 * @param key
	 * @return
	 */
	public boolean lock(String key,int seconds) 
		Boolean result = redisTemplate.opsForValue().setIfAbsent(key, System.currentTimeMillis(), seconds, TimeUnit.SECONDS);
		log.info("[] 加分布式锁,过期时间  秒,加锁结果 = ", key, seconds, result);
		return result;
	

	/**
	 * 解锁
	 * @param key
	 * @return
	 */
	public Boolean unlock(String key) 
		log.info(" 解锁", key);
		return  redisTemplate.opsForValue().getOperations().delete(key);

	

3、业务代码中使用分布式锁:
1)引用缓存工具类

    @Autowired
    private RedisTemplateService redisTemplateService;

2)方法中伪代码

        // 加锁,一般1个固定字符串加一个字段(具有唯一性)
        String key = REDIS_KEY + reserveId;
        boolean lock = redisTemplateService.lock(key, EXPIRETIME_10S);
        if (!lock) 
            log.error("key=加锁失败", key);
            throw new GlobalErrorInfoException(ErrorInfoEnum  .ORDER_RESERVATION_GET_LOCK_ERROR);
        
        try 
			// 业务代码
		 finally 
            //锁释放
            redisTemplateService.unlock(key);
        

4、涉及的常量:

	// 锁的key,根据自身业务自定义
    public static final String REDIS_KEY = "MT:RESERVE:";

    // 锁过期时间,根据方法逻辑处理复杂度自定义
    public static final Integer EXPIRETIME_10S = 10;
		

以上是关于分布式锁的实现工具类的主要内容,如果未能解决你的问题,请参考以下文章

Redis分布式锁的实现方式

万字长文带你解读Redisson分布式锁的源码

[redis分布式锁]redisson分布式锁的实现及spring-boot-starter封装

Redis分布式锁的实现原理

Redis分布式锁的实现原理

Redis分布式锁的实现原理