lua脚本做redis的锁

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 这段内容是关于使用Redis实现分布式锁的Java代码示例。`RedisLock`类包含`lock`和`unlock`方法,使用`StringRedisTemplate`和Lua脚本进行操作。代码展示了两种加锁方式:一种带有过期时间,另一种不带。还提到了在加锁和解锁过程中的异常处理,并提供了相关参考资料链接。

 

package com.wosai.upay.job.biz;
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.Arrays;
public class RedisLock {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private final static DefaultRedisScript<Long> LOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2])  else return 0 end"
            , Long.class
    );
    private final static DefaultRedisScript<Long> UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"
            , Long.class
    );
    
    public boolean lock(final String key, final String value, long timeInSeconds) {
        Long result = redisTemplate.execute(LOCK_LUA_SCRIPT, Arrays.asList(key), value, String.valueOf(timeInSeconds));
        return result == 1;
    }
    public boolean unlock(String key, String value) {
        Long result = redisTemplate.execute(UNLOCK_LUA_SCRIPT, Arrays.asList(key), value);
        return result != null && result == 1;
    }
}

image.gif

if (!redisLock.lock(key, value,”时间“)) {
            return;
        }
        try {
           //做业务
        } catch (Exception e) {
//业务处理
        } finally {
            redisLock.unlock(key, value);
        }

image.gif

不加过期时间的写法:

public boolean lock(final String key, final String value, long waitTimeMillis, long expireSeconds) throws InterruptedException {
        boolean success = false;
        long alreadyWaitTime = 0;
        while (true) {
            try {
                Long result = 0L;
                if (expireSeconds != 0) {
                    result = redisTemplate.execute(LOCK_LUA_SCRIPT_WITH_EXPIRE, Arrays.asList(key), value, String.valueOf(expireSeconds));
                } else {
                    result = redisTemplate.execute(LOCK_LUA_SCRIPT_NO_EXPIRE, Arrays.asList(key), value, String.valueOf(expireSeconds));
                }
                success = (result == 1);
            } catch (Exception e) {
                log.warn("加锁失败:{}", key, e);
            }
            if (success) {
                return true;
            }
            if (alreadyWaitTime >= waitTimeMillis) {
                return false;
            }
            Thread.sleep(10L);
            alreadyWaitTime = alreadyWaitTime + 10;
        }
    }
    public boolean unlock(String key, String value) {
        Long result = redisTemplate.execute(UNLOCK_LUA_SCRIPT, Arrays.asList(key), value);
        return result != null && result == 1;
    }
    private final static DefaultRedisScript<Long> LOCK_LUA_SCRIPT_WITH_EXPIRE = new DefaultRedisScript<>(
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2])  else return 0 end"
            , Long.class
    );
    private final static DefaultRedisScript<Long> LOCK_LUA_SCRIPT_NO_EXPIRE = new DefaultRedisScript<>(
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return 1 else return 0 end"
            , Long.class
    );
    private final static DefaultRedisScript<Long> UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"
            , Long.class
    );

image.gif

参考:RedisTemplate下Redis分布式锁引发的系列问题_redistemplate加锁其它写入有影响吗-CSDN博客

Redis分布式锁的实现方式(redis面试题)_Redis_脚本之家

redis分布式锁及会出现的问题解决_Redis_脚本之家

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
5天前
|
存储 NoSQL 调度
Redis Lua脚本:原子性的真相揭秘
【4月更文挑战第20天】
20 0
Redis Lua脚本:原子性的真相揭秘
|
27天前
|
存储 NoSQL 数据处理
Redis Lua脚本:赋予Redis更强大的逻辑与功能
Redis Lua脚本:赋予Redis更强大的逻辑与功能
|
20天前
|
存储 NoSQL 算法
09- Redis分片集群中数据是怎么存储和读取的 ?
Redis分片集群使用哈希槽分区算法,包含16384个槽(0-16383)。数据存储时,通过CRC16算法对key计算并模16383,确定槽位,进而分配至对应节点。读取时,根据槽位找到相应节点直接操作。
54 12
|
20天前
|
NoSQL Linux Redis
06- 你们使用Redis是单点还是集群 ? 哪种集群 ?
**Redis配置:** 使用哨兵集群,结构为1主2从,加上3个哨兵节点,总计分布在3台Linux服务器上,提供高可用性。
325 0
|
28天前
|
负载均衡 监控 NoSQL
Redis的集群方案有哪些?
Redis集群包括主从复制(基础,手动故障恢复)、哨兵模式(自动高可用)和Redis Cluster(官方分布式解决方案,自动分片和容错)。此外,还有如Codis、Redisson和Twemproxy等第三方工具用于代理和负载均衡。选择方案需考虑应用场景、数据规模和并发需求。
275 2
|
1月前
|
NoSQL Redis
Redis集群(六):集群常用命令及说明
Redis集群(六):集群常用命令及说明
233 0
|
2月前
|
运维 NoSQL 算法
Redis-Cluster 与 Redis 集群的技术大比拼
Redis-Cluster 与 Redis 集群的技术大比拼
121 0
|
5天前
|
存储 NoSQL 算法
Redis 搭建分片集群
Redis 搭建分片集群
14 2
|
28天前
|
NoSQL Java 测试技术
面试官:如何搭建Redis集群?
**Redis Cluster** 是从 Redis 3.0 开始引入的集群解决方案,它分散数据以减少对单个主节点的依赖,提升读写性能。16384 个槽位分配给节点,客户端通过槽位信息直接路由请求。集群是无代理、去中心化的,多数命令直接由节点处理,保持高性能。通过 `create-cluster` 工具快速搭建集群,但适用于测试环境。在生产环境,需手动配置文件,启动节点,然后使用 `redis-cli --cluster create` 分配槽位和从节点。集群动态添加删除节点、数据重新分片及故障转移涉及复杂操作,包括主从切换和槽位迁移。
33 0
面试官:如何搭建Redis集群?
|
1月前
|
存储 NoSQL 前端开发
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群指令分析—实战篇)
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群指令分析—实战篇)
11 0