SpringBoot整合Redis实现分布式锁

news2024/11/18 0:36:22

SpringBoot整合Redis实现分布式锁

分布式系统为什么要使用分布式锁?

首先,分布式系统是由多个独立节点组成的,这些节点可能运行在不同的物理或虚拟机器上,它们通过网络进行通信和协作。在这样的环境中,多个节点可能同时尝试访问和修改共享资源,这就可能导致数据不一致和并发冲突的问题。

为了解决这个问题,分布式锁被引入作为一种同步机制。分布式锁能够在分布式系统中提供全局唯一的锁,确保在任意时刻只有一个节点能够访问和修改共享资源。当节点需要访问共享资源时,它必须先获取分布式锁,如果锁已经被其他节点持有,则当前节点需要等待或执行其他操作。只有当节点成功获取到锁后,才能对共享资源进行访问和修改。

此外,分布式锁还可以帮助实现一些复杂的分布式系统需求,如分布式事务、分布式缓存一致性等。通过使用分布式锁,我们可以更好地控制并发访问,保证数据的一致性和完整性,提高系统的可靠性和稳定性。

实现分布式锁需要考虑到多种因素,如锁的粒度、锁的公平性、锁的释放机制等。同时,由于分布式系统的复杂性和不确定性,分布式锁的实现也可能存在一些挑战和限制,如网络延迟、节点故障等问题都可能导致锁的行为变得复杂和难以预测。因此,在使用分布式锁时,我们需要根据实际情况进行权衡和选择,确保能够满足系统的需求并避免潜在的问题。

分布式系统使用分布式锁是为了实现资源的同步访问和并发控制,保证数据的一致性和完整性,提高系统的可靠性和稳定性。

redis配置类

package com.test.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2023-06-09 10:58
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

}


分布式锁工具类

package com.test.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-03-08 14:33
 */
@Component
public class RedisDistributedLock {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {
        return stringRedisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean releaseDistributedLock(String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                "return redis.call('del', KEYS[1]) " +
                "else " +
                "return 0 " +
                "end";
        Long result = stringRedisTemplate.execute(
                new DefaultRedisScript<Long>(script, Long.class),
                Collections.singletonList(lockKey),
                requestId);
        System.out.println(result);
        return result.equals(1L);
    }
}

定时任务测试分布式锁

package com.test.service;

import com.test.config.RedisDistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-03-08 14:44
 */
@Service
public class TestService {

    @Autowired
    private RedisDistributedLock redisDistributedLock;

    @Scheduled(cron = "0/10 * * * * ?")
    //@Scheduled(cron = "0 10 16 * * ?")
    @Transactional(rollbackFor = Exception.class)
    public void testLock(){
        System.out.println("进入分布式锁方法");
        // 尝试获取分布式锁
        if (redisDistributedLock.tryGetDistributedLock("tangshuai", "123", 30)) {
                System.out.println("释放分布式锁");
                redisDistributedLock.releaseDistributedLock("tangshuai", "123");
        } else {
            // 未能获取到锁,可以选择重试或返回失败
            throw new RuntimeException("未能获取到锁,请重试");
        }
    }
}

分别启动两个相同的服务

package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2023-06-08 17:04
 */
@SpringBootApplication
@EnableScheduling
public class SaTokenDemoApp {
    public static void main(String[] args) {
        SpringApplication.run(SaTokenDemoApp.class, args);
    }
}


查看两个控制台打印情况,两个服务谁谁拿到锁,谁开始执行业务代码,没拿到锁的服务抛出异常

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1501328.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端实现单点登录

简单概括就是&#xff0c;一个系统登录&#xff0c;跳转多个系统&#xff0c;其他系统不需要再登录&#xff0c;直接进入页面 登录的系统 <template><div><div class"content"><div class"item" v-for"(item,index) in list&q…

Android使用WebView打开内嵌H5网页

Android打开外部网页链接请参考上一篇文章 https://public.blog.csdn.net/article/details/136384559 继上篇&#xff0c;新建assets文章夹&#xff0c;将H5的网页资源放到此文件夹下 把H5的资源文件都拷进来 这个时候&#xff0c;将添加打开本地网页的代码&#xff1a; //打…

【HTML】HTML基础8.1(表单标签)

目录 效果 基础知识 标签 ① ② 代码 效果 基础知识 表单的组成元素 表单控件用户所填写的信息提示信息提示用户需要填的信息表单域包含表单元素的区域 标签 ① <form action"" method""></form> <form>标签确定了一个表单域&…

【Linux】第四十站:线程概念

文章目录 一、线程二、Linux中线程应该如何理解三、重新定义线程四、四谈进程地址空间&#xff08;页表相关&#xff09;五、Linux线程周边的概念1. 线程与进程切换2.线程优点3.线程缺点4.线程异常5.线程用途 一、线程 线程&#xff1a;是进程内的一个执行分支。线程的执行粒度…

阿里云DSW做AI绘画时的显卡选择A10?V100?

V100是Volta架构&#xff0c;A10是Ampere架构&#xff0c;架构上讲A10先进点&#xff0c;其实只是制程区别&#xff0c;用起来没区别。 V100是HBM的内存读取&#xff0c;带宽大&#xff0c;但是DDR5的。 二块卡都是全精度为主的算力卡&#xff0c;半精度优势不明显。 需要用…

Spring学习 基础(二)Bean和AOP

3、Spring Bean Bean 代指的就是那些被 IoC 容器所管理的对象&#xff0c;我们需要告诉 IoC 容器帮助我们管理哪些对象&#xff0c;这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。 Bean的创建方式 1. XML 配置文件&#xff1a; 传统上&am…

Learn OpenGL 02 你好,三角形

图形渲染管线 图形渲染管线的每个阶段的抽象展示。要注意蓝色部分代表的是我们可以注入自定义的着色器的部分 首先&#xff0c;我们以数组的形式传递3个3D坐标作为图形渲染管线的输入&#xff0c;用来表示一个三角形&#xff0c;这个数组叫做顶点数据(Vertex Data)。 顶点着色…

最新2024年阿里云服务器地域和可用区全球分布表,不只是中国

2024年最新阿里云服务器地域分布表&#xff0c;地域指数据中心所在的地理区域&#xff0c;通常按照数据中心所在的城市划分&#xff0c;例如华北2&#xff08;北京&#xff09;地域表示数据中心所在的城市是北京。阿里云地域分为四部分即中国、亚太其他国家、欧洲与美洲和中东&…

superset连接Apache Spark SQL(hive)过程中的各种报错解决

superset连接数据库官方文档&#xff1a;Installing Database Drivers | Superset 我们用的是Apache Spark SQL&#xff0c;所以首先需要安装下pyhive #命令既下载了pyhive也下载了它所依赖的其他安装包 pip install pyhive#多个命令也可下载 pip install sasl pip install th…

设计模式-结构型模式-代理模式

代理模式&#xff08;Proxy&#xff09;&#xff0c;为其他对象提供一种代理以控制对这个对象的访问。[DP] // 定义接口 interface Subject {void request(); }// 真实主题对象 class RealSubject implements Subject {Overridepublic void request() {System.out.println(&quo…

App自动化测试笔记(十一):综合案例

短信案例 需求 在《短信》应用中&#xff0c;进入发送短信页面&#xff0c;在姓名和内容栏中&#xff0c;输入对应的数据&#xff0c;并点击发送。 包名界面名&#xff1a;com.android.mms/.ui.ConversationList 发送短信页面标识&#xff1a;resource-id&#xff0c;com.and…

乐得瑞 1C to 2C快充线:引领充电数据线新潮流,高效快充解决接口难题

随着科技的不断进步&#xff0c;数据线的接口种类也日渐繁多&#xff0c;但在早些时候&#xff0c;三合一和二合一的数据线因其独特的设计而备受欢迎。这类数据线通常采用USB-A口作为输入端&#xff0c;并集成了Micro USB、Lightning以及USB-C三种接口&#xff0c;满足了当时市…

【二】【算法分析与设计】编程练习

数字三角形 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 32768K&#xff0c;其他语言65536K 64bit IO Format: %lld 题目描述 KiKi学习了循环&#xff0c;BoBo…

2024年AI辅助研发趋势深度分析

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;其在各个行业领域中的应用也日益广泛。特别是在研发领域&#xff0c;AI已经成为变革的先锋&#xff0c;极大地推动了科技进步的步伐。本文将从技术进展、行业应用案例、面临的挑战与机遇、未来趋势预测、法规…

JavaScript实现小球移动(二)

这次采用了封装函数的方法&#xff0c;将小球向左向右移动封装在同一个函数内。 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

接雨水(leetcode hot100)

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] …

‘ jupyter ‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

安装anaconda后&#xff0c;在 Dos黑窗口 运行 jupyter notebook 的两个问题 原因&#xff1a;没配置环境变量 解决方法&#xff1a; 在 系统环境变量Path 中 添加两个地址 这里以anaconda安装在 D:\anaconda\install 下为例 &#xff08;根据个人安装具体位置而定&#xff…

Centos7.9安装glibc2.18后回滚到glibc2.17

对glibc的操作非常危险&#xff0c;如果您对Linux操作系统的操作仅限于查看别人的资料来解决问题的话&#xff0c;我还是比较真诚的劝退你了。只所以还是写下这篇博文&#xff0c;一是为了记录自己排错的过程&#xff0c;二是更正目前网络中一些不太正确的博文&#xff0c;防止…

史上最全AP/mAP通用代码实现(yolov5 txt版本)-下

提示&#xff1a;通用map指标框架代码介绍&#xff0c;直接使用yolov5数据格式&#xff0c;实现论文map指标计算代码解读 文章目录 前言该版本是直接使用yolo数据格式实现map计算&#xff0c;集成txt转json格式内容。 一、map模块整体认识二、map计算应用代码解读三、通用map计…

指针进阶(4)看一下这些与指针有关的题你都会做吗?

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…