SpringBoot结合Redis实现的分布式锁

本文探讨了在SpringBoot应用中使用RedisTemplate、Lua脚本以及Redisson库来实现分布式锁的方法,强调了不同实现的优缺点,特别是Redisson提供的全面锁类型和简化使用的特性。
摘要由CSDN通过智能技术生成
一、使用RedisTemplate的简单实现


1.在Spring Boot应用程序中添加Redis依赖项

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.创建一个Redis分布式锁实现的类,示例代码:

@Serice
public class RedisLockSerice {

  @Autowired
  private RedisTemplate<String, String> redisTemplate;

  public boolean lock(String key, String value, long expireTime) {
    Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.MILLISECONDS);
    return success != null && success;
  }

  public void unlock(String key, String value) {
    String currentValue = redisTemplate.opsForValue().get(key);
    if (currentValue != null && currentValue.equals(value)) {
      redisTemplate.delete(key);
    }
  }
}


3. 这种方案的缺陷:
锁的释放方式不够安全。在unlock() 方法中,只是简单地通过 RedisTemplate 的 delete() 方法删除了 Redis 中的 key-value 对,但是这种方式存在一定的风险,因为可能存在删除了其他线程获取的锁的情况。

二、使用RedisTemplate及Lua脚本的实现


1. 使用Lua脚本,创建一个Redis分布式锁实现的类,示例代码:

@Service
public class RedisLockService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    //获取锁的 Lua 脚本
    private static final String LOCK_SCRIPT =
            "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then " +
                    "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                    "return true; " +
                    "else return false; " +
                    "end";

    //释放锁的 Lua 脚本
    private static final String UNLOCK_SCRIPT =
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                    "redis.call('del', KEYS[1]); " +
                    "return true; " +
                    "else return false; " +
                    "end";

    public boolean lock(String key, String value, Long expire) {
        String[] keys = {key};
        String[] args = {value, String.valueOf(expire)};
        RedisScript<Boolean> script = new DefaultRedisScript<>(LOCK_SCRIPT, Boolean.class);
        Boolean result = redisTemplate.execute(script, Arrays.asList(keys), args);
        return result != null && result;
    }

    public boolean unlock(String key,String value){
        String[] keys = {key};
        String[] args = {value};
        RedisScript<Boolean> script = new DefaultRedisScript<>(UNLOCK_SCRIPT, Boolean.class);
        Boolean result = redisTemplate.execute(script, Arrays.asList(keys), args);
        return result != null && result;
    }
}


这种方案是使用Redis实现分布式锁比较常见的方式。

三、集成Redisson实现分布式锁


Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的 Java 常用对象,还实现了可重入锁(Reentrant Lock)、公平锁(Fair Lock、联锁(MultiLock)、 红锁(RedLock)、 读写锁(ReadWriteLock)等,还提供了许多分布式服务。Redisson 提供了使用 Redis 的最简单和最便捷的方法。Redisson 的宗旨是促进使用者对 Redis 的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
1. 在Spring Boot应用程序中添加Redisson依赖:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>{redisson-version}</version>
</dependency>

2.创建一个Redisson分布式锁实现的类,示例代码:

@Service
@Slf4j
public class RedissonLockService {
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 尝试在指定时间内获取分布式锁
     * @param key
     * @param waitTime (s)
     * @param expire(ms)
     * @return
     */
    public boolean lock(String key, int waitTime, Long expire) {
        RLock lock = redissonClient.getLock(key);
        log.info("lock:" + lock);
        try {
            //lock.lock(expire, TimeUnit.MILLISECONDS); //lock 会一直阻塞
            //lock.tryLock(expire, TimeUnit.MILLISECONDS); //tryLock 如果不指定WaitTime的話,也是阻塞模式
            return lock.tryLock(waitTime, expire, TimeUnit.MILLISECONDS);
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 释放分布式锁
     * @param key
     * @return
     */
    public void unlock(String key){
        RLock lock = redissonClient.getLock(key);
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
            log.info("unlock come here...");
        }
        else{
            log.info("no need to unlock...");
        }
    }
}

3.使用Redisson分布式加锁的三/四步:
第一步主要是获取RLock对象。
第二步尝试加锁,加锁失败,返回加锁失败。
第三步就是我们业务代码。
第四步释放锁。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

u010303355

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值