Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis SETNX实现分布式锁

Redis使用SETNX命令实现分布式锁

作者:ppo92

分布式锁是一种用于在分布式系统中控制多个节点对共享资源进行访问的机制,本文主要为大家详细介绍了Redis如何使用SETNX命令实现分布式锁,需要的可以参考下

什么是分布式锁

分布式锁是一种用于在分布式系统中控制多个节点对共享资源进行访问的机制。在分布式系统中,由于多个节点可能同时访问和修改同一个资源,因此需要一种方法来确保在任意时刻只有一个节点能够对资源进行操作,以避免数据不一致或冲突。分布式锁就是用来实现这种互斥访问的工具。

为什么 Redis 的 SETNX 可以实现分布式锁

Redis 的 SETNX 命令(即 SET if Not eXists)可以用来实现分布式锁,原因如下:

准备工作

创建一个Spring Boot项目,并引入相关依赖

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

application.yml文件中配置 Redis 连接信息:

server:
  port: 8080
spring:
  redis:
    host: xxx.xxx.xxx.xxx
    port: 6379
    password: xxxxxx

具体实现

创建分布式锁工具类

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class DistributedLock {

    private final StringRedisTemplate redisTemplate;

    // 通过构造函数注入 StringRedisTemplate
    public DistributedLock(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey    锁的键
     * @param requestId  请求标识,用于区分不同的锁持有者
     * @param expireTime 锁的过期时间,单位为毫秒
     * @return 如果成功获取锁,返回 true;否则返回 false
     */
    public boolean acquireLock(String lockKey, String requestId, long expireTime) {
        // 使用 setIfAbsent 方法尝试设置键值对,如果键不存在则设置成功并返回 true,否则返回 false
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.MILLISECONDS);
        return result != null && result;
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey   锁的键
     * @param requestId 请求标识,用于确保只有锁的持有者才能释放锁
     * @return 如果成功释放锁,返回 true;否则返回 false
     */
    public boolean releaseLock(String lockKey, String requestId) {
        // 获取当前锁的值
        String currentValue = redisTemplate.opsForValue().get(lockKey);
        // 检查当前锁的值是否等于请求标识,确保只有锁的持有者才能释放锁
        if (currentValue != null && currentValue.equals(requestId)) {
            // 删除锁键
            return redisTemplate.delete(lockKey);
        }
        return false;
    }
}

创建业务类用来测试

import com.wh.demo01.demos.web.utils.DistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class MyRedisService {

    private final DistributedLock distributedLock;

    // 通过构造函数注入 DistributedLock
    @Autowired
    public MyRedisService(DistributedLock distributedLock) {
        this.distributedLock = distributedLock;
    }

    /**
     * 模拟需要同步执行的方法
     */
    public void someMethod() {
        String lockKey = "myLockKey";
        String requestId = "uniqueRequestId";
        long expireTime = 10000; // 10 seconds

        try {
            // 尝试获取锁
            if (distributedLock.acquireLock(lockKey, requestId, expireTime)) {
                // 获取到锁,执行需要同步的操作
                System.out.println(new Date() + "获取锁成功");
                // 模拟业务操作
                Thread.sleep(5000);
            } else {
                System.out.println(new Date() + "获取锁失败");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 确保锁在操作完成后被释放
            distributedLock.releaseLock(lockKey, requestId);
        }
    }
}

创建Controller

import com.wh.demo01.demos.web.service.MyRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/redis")
public class RedisController {

    @Autowired
    private MyRedisService service;

    @GetMapping("/test")
    public void TestRedis(){
        service.someMethod();
    }
}

整个项目结构如下:

使用idea的复制配置功能将该服务复制一份,并指定端口为8081,模拟分布式服务:

使用接口调试工具分别向80808081端口发送请求:

结果如下:

可见在分布式锁的影响下,someMethod方法在10秒内只能被调用一次。

到此这篇关于Redis使用SETNX命令实现分布式锁的文章就介绍到这了,更多相关Redis SETNX实现分布式锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文