首页 > 数据库 >Springboot(五十四)SpringBoot3实现redis分布式锁

Springboot(五十四)SpringBoot3实现redis分布式锁

时间:2024-12-20 14:57:45浏览次数:6  
标签:脚本 return Springboot KEYS redis redisKey lua SpringBoot3

我们在Springboot项目中分别整合了redis和redission框架。

 

下边我记录一下再框架中分别使用redis和redission实现分布式锁的代码。

 

一:redis-lua脚本实现分布式锁

lua本身是不具备原子性的,但由于Redis的命令是单线程执行的,它会把整个Iua脚本作为一个命令执行,会阻塞其间接受到的其他命令,这就保证了lua脚本的原子性。

 

Lua脚本好处:

1)      原子性:Lua脚本的所有命令在执行过程中是原子的,避免了并发修改带来的问题。

2)      减少网络往返次数:通过在服务器端执行脚本,减少了客户端和服务器之间的网络往返次数,提高了性能。

3)      复杂操作:可以在Lua脚本中执行复杂的逻辑,超过了单个Redis命令的能力。

lua脚本使用注意点

1)      由于Redis执行lua脚本其间,无法处理其他命令,因此如果lua脚本的业务过于复杂,则会产生长时间的阻塞,因此编写Lua脚本时应尽量保持简短和高效。

2)      Redis默认限制lua执行脚本时间为5s,如果超过这个时间则会终止且抛错,可以通过lua-time-limit调整时长。

 

但是,redis-lua分布式锁有一个小小的问题,他不具备可重入性。针对这个问题,我对redis-lua分布式锁实现了封装。代码如下所示:

RedisLuaUtils.java

package com.modules.redis.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author camellia
 * redis 加锁工具类
 */
@Slf4j
public class RedisLuaUtils
{
    /**
     * 超时时间(毫秒)
     */
    private static final long TIMEOUT_MILLIS = 15000;

    /**
     * 重试次数
     */
    private static final int RETRY_TIMES = 10;

    /***
     * 睡眠时间(重试间隔)
     */
    private static final long SLEEP_MILLIS = 100;

    /**
     * 用来加锁的lua脚本
     * 因为新版的redis加锁操作已经为原子性操作
     * 所以放弃使用lua脚本
     */
    private static final String LOCK_LUA =
            "if redis.call(\"setnx\",KEYS[1],ARGV[1]) == 1 " +
                    "then " +
                    " return redis.call('expire',KEYS[1],ARGV[2]) " +
                    "else " +
                    " return 0 " +
                    "end";

    /**
     * 用来释放分布式锁的lua脚本
     * 如果redis.get(KEYS[1]) == ARGV[1],则redis delete KEYS[1]
     * 否则返回0
     * KEYS[1] , ARGV[1] 是参数,我们只调用的时候 传递这两个参数就可以了
     * KEYS[1] 主要用來传递在redis 中用作key值的参数
     * ARGV[1] 主要用来传递在redis中用做 value值的参数
     */
    private static final String UNLOCK_LUA =
            "if redis.call(\"get\",KEYS[1]) == ARGV[1] "
                    + "then "
                    + " local number = redis.call(\"del\", KEYS[1]) "
                    + " return tostring(number) "
                    + "else "
                    + " return tostring(0) "
                    + "end ";

    /**
     * 检查 redisKey 是否上锁(没加锁返回加锁)
     *
     * @param redisKey redisKey
     * @param template template
     * @return Boolean
     */
    public static Boolean isLock(String redisKey, String value, RedisTemplate<Object, Object> template)
    {

        return lock(redisKey, value, template, RETRY_TIMES);
    }

    private static Boolean lock(String redisKey, String value, RedisTemplate<Object, Object> template, int retryTimes)
    {
        boolean result = lockKey(redisKey, value, template);

        // 循环等待上一个用户锁释放,或者锁超时释放
        while (!(result) && retryTimes-- > 0)
        {
            try
            {
                log.debug("lock failed, retrying...{}", retryTimes);
                Thread.sleep(RedisLuaUtils.SLEEP_MILLIS);
            }
            catch (InterruptedException e)
            {
                return false;
            }
            result = lockKey(redisKey, value, template);
        }

        return result;
    }

    /**
     * 加锁
     * @

标签:脚本,return,Springboot,KEYS,redis,redisKey,lua,SpringBoot3
From: https://blog.csdn.net/qq_39708228/article/details/144500158

相关文章

  • 怎么利用Redis实现延时队列?
    1.什么是延时队列?延时队列是一种特殊的队列结构,它存储的元素需要在经过一段延迟时间后才能被处理。比如,在电商系统中,下单后30分钟未支付就自动取消订单;或者在消息通知系统中,定时发送提醒消息等场景都可以使用延时队列来实现。2.Redis使用Zset(有序集合)来实现延时队列原理......
  • Java项目实战之基于springboot+vue+mysql+jpa+redis的企业网站搭建设计文档设计与实现
    一、引言1.1项目背景随着互联网的飞速发展,企业网站已成为企业展示形象、推广产品和服务、与客户沟通的重要窗口。为了提升企业的竞争力,需要构建一个功能完善、用户体验良好的企业网站。1.2项目目标本项目旨在打造一个专业、高效、易用的企业网站,满足企业在品牌展示、产品推......
  • 【9654】基于springboot+vue的家政服务管理平台
    作者主页:Java码库主营内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。收藏点赞不迷路 关注作者有好处文末获取源码项目描述家政服务管理平台是一个管理信息系统,为了宣传的需要,为了给用户提供方便快捷的......
  • 【9655】基于springboot+vue的留守儿童爱心网站
    作者主页:Java码库主营内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。收藏点赞不迷路 关注作者有好处文末获取源码项目描述留守儿童爱心网站是一个管理信息系统,为了宣传的需要,为了给用户提供方便快捷的......
  • 【计算机毕业设计】基于Springboot的老年医疗保健系统+LW+PPT
    博主介绍:✌全网粉丝3W+,csdn特邀作者、CSDN新星计划导师、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视......
  • Redis缓存中的 雪崩、穿透、击穿、热点和数据倾斜(详细例子)
    在使用Redis作为缓存时,了解一些常见问题是非常重要的,包括雪崩、穿透、击穿、热点和数据倾斜。以下是详细讲解及示例。1.缓存雪崩定义缓存雪崩是指在某一时刻,大量缓存数据同时过期,导致大量请求直接访问数据库,从而造成数据库的压力骤增,可能导致数据库崩溃。示例假设一个......
  • 如何安装Redis???(详细过程+命令行)
    目录1.安装Redis在Windows上使用Windows子系统(WSL)使用RedisWindows版本在Linux上在macOS上2.启动Redis服务器在Windows上在Linux和macOS上3.验证Redis是否运行4.停止Redis服务器1.安装Redis如果你还没有安装Redis,可以根据你的操作系统选择合适的......
  • 基于springboot的居家养老居家看护小程序设计
     目录一、整体目录:项目包含源码、调试、修改教程、调试教程、讲解视频、开发文档(项目摘要、前言、技术介绍、可行性分析、流程图、结构图、ER属性图、数据库表结构信息、功能介绍、测试致谢等约1万字)二、运行截图三、代码部分(示范):四、数据库表(示范):数据库表有注释,可以......
  • Redis中的SpringDataRedis 序列化和反序列化及API命令(详细讲解+代码)
    目录API函数SpringDataRedis序列化SpringDataRedis反序列化概念 在SpringDataRedis中,序列化和反序列化是关键操作,选择合适的序列化方式可以提高性能和兼容性。根据具体需求,可以使用默认的序列化方式,或自定义序列化器来满足特定要求。1.序列化和反序列化的基本......
  • 【2025】基于springboot+vue3的在线考试系统源码设计
    目录一、整体目录(示范):文档含项目技术介绍、E-R图、数据字典、项目功能介绍与截图等二、运行截图三、代码部分(示范):四、数据库表(示范):数据库表有注释,可以导出数据字典及更新数据库时间,欢迎交流学习五、主要技术介绍:六、项目调试学习(点击查看)七、项目交流一、教育信......