SpringBoot集成redis实现分布式锁的示例代码

 更新时间:2021年1月25日 10:00  点击:2520

1、准备

使用redis实现分布式锁,需要用的setnx(),所以需要集成Jedis

需要引入jar,jar最好和redis的jar版本对应上,不然会出现版本冲突,使用的时候会报异常redis.clients.jedis.Jedis.set(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;

我使用的redis版本是2.3.0,Jedis使用的是3.3.0

    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>3.3.0</version>
    </dependency>

2、配置参数

spring:
  redis:
    host: localhost
    port: 6379
    password: root
    timeout: 5000
    # Redis数据库索引(默认为0)
    database: 0
    # 连接池最大连接数(使用负值表示没有限制)
    jedis:
      pool:
      # 连接池最大连接数(使用负值表示没有限制)
      max-active: 8
      # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-wait: -1
      # 连接池中的最大空闲连接
      max-idle: 8
      # 连接池中的最小空闲连接
      min-idle: 0
      # 获取连接时检测是否可用
      testOnBorrow: true

3、配置JedisPool

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
 
/**
 * Jedis配置项
 * @autho ConnorSong
 * @date 2021/1/21 9:55 上午
 */
@Configuration
@Slf4j
public class JedisPoolCinfigration {
 
  @Bean
  public JedisPoolConfig jedisPoolConfig(@Value("${spring.redis.jedis.pool.max-active}") int maxActive,
                      @Value("${spring.redis.jedis.pool.max-idle}") int maxIdle,
                      @Value("${spring.redis.jedis.pool.min-idle}") int minIdle,
                      @Value("${spring.redis.jedis.pool.max-wait}") long maxWaitMillis,
                      @Value("${spring.redis.jedis.pool.testOnBorrow}") boolean testOnBorrow) {
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxTotal(maxActive);
    jedisPoolConfig.setMaxIdle(maxIdle);
    jedisPoolConfig.setMinIdle(minIdle);
    jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
    jedisPoolConfig.setTestOnBorrow(testOnBorrow);
 
    return jedisPoolConfig;
  }
 
  @Bean
  public JedisPool jedisPool(@Value("${spring.redis.host}") String host,
                @Value("${spring.redis.password}") String password,
                @Value("${spring.redis.port}") int port,
                @Value("${spring.redis.timeout}") int timeout, JedisPoolConfig jedisPoolConfig) {
 
    log.info("=====创建JedisPool连接池=====");
    if (StringUtils.isNotEmpty(password)) {
      return new JedisPool(jedisPoolConfig, host, port, timeout, password);
    }
 
    return new JedisPool(jedisPoolConfig, host, port, timeout);
 
  }
}

4、分布式锁工具类

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
 
import java.util.Collections;
 
/**
 * jedis分布式锁工具类
 * @autho ConnorSong
 * @date 2021/1/20 6:26 下午
 */
@Slf4j
public class JedisLockUtils {
 
  private static final String LOCK_SUCCESS = "OK";
 
  private static final Long RELEASE_SUCCESS = 1L;
  /**
   * 尝试获取分布式锁
   * @param jedis Redis客户端
   * @param lockKey 锁
   * @param lockValue value
   * @param expireTime 超期时间(秒)
   * @return 是否获取成功
   */
  public static boolean tryGetLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
    log.info("----获取Jedis分布式锁----lockKey:{}", lockKey);
 
    try {
      //方案一,具有原子性,并且可以设置过期时间,避免拿到锁后,业务代码出现异常,无法释放锁
      String result = jedis.set(lockKey, lockValue, new SetParams().nx().ex(expireTime));
      if (LOCK_SUCCESS.equals(result)) {
        return true;
      }
      return false;
      //方案二,setnx()具有原子性,但是有后续判断,整体不具有原子性,不能设置过期时间
//      //setnx(lockkey, 当前时间+过期超时时间),如果返回 1,则获取锁成功;如果返回 0 则没有获取到锁
//      String value = new Date().getTime() + expireTime + "";
//      if(1 == jedis.setnx(lockKey, value)){
//        return true;
//      }else{
//        String oldExpireTime = jedis.get(lockKey);
//        if(Long.valueOf(oldExpireTime)< new Date().getTime()){
//          //锁超时,可以获取锁重新设置锁
//          //计算 newExpireTime = 当前时间+过期超时时间,然后 getset(lockkey, newExpireTime) 会返回当前 lockkey的值currentExpireTime
//          long newExpireTime = new Date().getTime() + expireTime;
//          String currentExpireTime = jedis.getSet(lockKey, newExpireTime + "");
//          if(currentExpireTime.equals(oldExpireTime)){
//            return true;
//          }
//        }
//        return false;
//      }
    }finally {
      returnResource(jedis);
    }
  }
 
  /**
   * 释放分布式锁
   * @param jedis Redis客户端
   * @param lockKey 锁
   * @return 是否释放成功
   */
  public static boolean closeLock(Jedis jedis, String lockKey, String lockValue) {
    log.info("----释放Jedis分布式锁----lockKey:{}, lockValue:{}", lockKey, lockValue);
    try {
      String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
      Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(lockValue));
      if (RELEASE_SUCCESS.equals(result)) {
        return true;
      }
      return false;
    }finally {
      returnResource(jedis);
    }
  }
 
  /**
   * 关闭资源
   * @param jedis
   */
  public static void returnResource(final Jedis jedis){
    if(null != jedis){
      jedis.close();
    }
  }
}

到此这篇关于SpringBoot集成redis实现分布式锁的示例代码的文章就介绍到这了,更多相关SpringBoot redis分布式锁内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞! 

[!--infotagslink--]

相关文章

  • 解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题

    这篇文章主要介绍了解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-28
  • Redis连接池配置及初始化实现

    这篇文章主要介绍了Redis连接池配置及初始化实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-29
  • 详解如何清理redis集群的所有数据

    这篇文章主要介绍了详解如何清理redis集群的所有数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
  • 详解redis desktop manager安装及连接方式

    这篇文章主要介绍了redis desktop manager安装及连接方式,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-15
  • SpringBoot实现excel文件生成和下载

    这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
  • 浅谈redis key值内存消耗以及性能影响

    这篇文章主要介绍了浅谈redis key值内存消耗以及性能影响,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-07
  • 详解springBoot启动时找不到或无法加载主类解决办法

    这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
  • lua读取redis数据的null判断示例代码

    最近在工作中遇到了一个问题,通过查找相关资料才得知原因是因为返回结果的问题,下面这篇文章主要给大家介绍了关于lua读取redis数据的null判断的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2020-06-30
  • SpringBoot集成Redis实现消息队列的方法

    这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
  • redis setIfAbsent和setnx的区别与使用说明

    这篇文章主要介绍了redis setIfAbsent和setnx的区别与使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-04
  • 解决Springboot get请求是参数过长的情况

    这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • Springboot+TCP监听服务器搭建过程图解

    这篇文章主要介绍了Springboot+TCP监听服务器搭建过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-28
  • Redis的Expire与Setex区别说明

    这篇文章主要介绍了Redis的Expire与Setex区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-15
  • Spring Boot项目@RestController使用重定向redirect方式

    这篇文章主要介绍了Spring Boot项目@RestController使用重定向redirect方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-02
  • springBoot 项目排除数据库启动方式

    这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10
  • springboot中使用@Transactional注解事物不生效的坑

    这篇文章主要介绍了springboot中使用@Transactional注解事物不生效的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26
  • SpringBoot接口接收json参数解析

    这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
  • 详解SpringBoot之访问静态资源(webapp...)

    这篇文章主要介绍了详解SpringBoot之访问静态资源(webapp...),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-14
  • 查看Redis内存信息的命令

    Redis 是一个开源、高性能的Key-Value数据库,被广泛应用在服务器各种场景中。本文介绍几个查看Redis内存信息的命令,包括常用的info memory、info keyspace、bigkeys等。...2021-01-15
  • springboot多模块包扫描问题的解决方法

    这篇文章主要介绍了springboot多模块包扫描问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16