当前位置: 代码网 > it编程>数据库>Redis > Redis使用SETNX命令实现分布式锁

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

2025年01月17日 Redis 我要评论
什么是分布式锁分布式锁是一种用于在分布式系统中控制多个节点对共享资源进行访问的机制。在分布式系统中,由于多个节点可能同时访问和修改同一个资源,因此需要一种方法来确保在任意时刻只有一个节点能够对资源进行

什么是分布式锁

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

为什么 redis 的 setnx 可以实现分布式锁

redis 的 setnx 命令(即 set if not exists)可以用来实现分布式锁,原因如下:

  • 原子性setnx 是一个原子操作,这意味着在同一时间只有一个客户端能够成功设置键值对。如果键已经存在,setnx 将不会执行任何操作。这种原子性确保了锁的获取和释放是线程安全的。
  • 唯一性setnx 确保了锁的唯一性。只有第一个尝试设置键的客户端能够成功,其他客户端在尝试设置相同的键时会失败。这模拟了锁的“获取”和“释放”行为。
  • 过期时间:通过结合 expire 命令或使用 set 命令的 ex 选项,可以为锁设置一个过期时间。这防止了锁被永久占用,即使客户端在持有锁期间崩溃或未能正确释放锁。
  • 分布式环境:redis 是一个分布式内存数据库,可以在多个节点之间共享数据。因此,使用 redis 实现的锁可以在分布式系统中的多个节点之间共享,从而实现分布式锁。
  • 高性能:redis 是一个高性能的数据库,能够处理大量的并发请求。这使得 redis 非常适合作为分布式锁的实现基础。

准备工作

创建一个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实现分布式锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com