LUA脚本

目录

一、Lua脚本

Lua脚本中可以编写多条Redis命令,确保多条命令共同执行时是一个原子操作

1.编写脚本:

Lua执行redis命令的语法:redis.call('命令名称', 'key', '其它参数',...)

lua 复制代码
-- 释放锁的lua脚本
-- 锁的key
local key = KEYS[1]
-- 当前线程标识
local threadId = ARGV[1]

-- 获取锁中的线程标识
local id = redis.call('get',key)
-- 比较线程标识与锁中的标识是否一致
if(id == threadId) then
    -- 释放锁
    return redis.call('del', key)
end

return 0

2.调用脚本:

语法:EVAL 脚本内容字符串 参数数量 key [key...] arg [arg...]

脚本中的key、value可以作为参数传递,key类型参数会放入KEYS数组,其它参数会放入ARGV数组,使用数组下标取值,默认下标从1开始

java 复制代码
// 不加参数(无形参)
EVAL "return redis.call('set', 'name', 'jack')" 0
// 加参数
EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 name jack

StringRedisTemplate调用Lua脚本的API如下:

java 复制代码
// 调用lua脚本释放锁
public void unlock1(String name) {
    // RedisScript是一个脚本类,用来接收lua脚本文件
    DefaultRedisScript<Long> unlock_script = new DefaultRedisScript<>();
    // ClassPath默认是resources文件夹,设置lua脚本文件位置
    unlock_script.setLocation(new ClassPathResource("unlock.lua"));
    // 设置lua脚本的返回值
    unlock_script.setResultType(Long.class);

    // 调用lua脚本,注意KEYS传的是List集合
    stringRedisTemplate.execute(unlock_script, Collections.singletonList("lock:" + name), String.valueOf(Thread.currentThread().getId()));
}

3.Lua实现可重入锁:

3.1 获取锁:

lua 复制代码
local key = KEYS[1]; --锁的key,一人一单问题就是用户id,同一用户的多个线程竞争同一把锁
local threadId = ARGV[1]; --持有锁的线程标识
local releaseTime = ARGV[2]; --锁的有效期

--锁是未被占有
if(redis.call('exists', key)==0) then
    redis.call('hset', key, theadId, '1'); --获取锁
    redis.call('expire', key, releaseTime); --设置有效期
    return 1; --返回表示获取成功
end;

--锁已被占有,且锁是本线程占有的
if(redis.call('hexists', key, threadId)==1) then
    redis.call('hincrby', key, threadId, '1'); --重入计数自增1
    redis.call('expire', key, releaseTime); --重置有效期
    return 1;
end;

--锁已被占有,且不是本线程占有的
return 0;

3.2 释放锁:

lua 复制代码
local key = KEYS[1]; --锁的key,一人一单问题就是用户id,同一用户的多个线程竞争同一把锁
local threadId = ARGV[1]; --持有锁的线程标识
local releaseTime = ARGV[2]; --锁的有效期

--当前锁不是被本线程持有
if(redis.call('hexists', key, threadId)==0) then
    return nil;
end;

--当前所被本线程持有
local count = redis.call('hincrby', key, threadId, -1); --可重入次数-1
--可重入次数是否减为0
if(count>0) then
    redis.call('expire', key, releaseTime) --重置有效期
    return nil;
else
    redis.call('del', key)
end;

return nil;    
相关推荐
恋恋西风2 小时前
C++ 理解 std::thread 在单核和多核上的行为差异
开发语言·c++
Brilliantwxx2 小时前
【Linux】 进程(9)程序与进程地址空间(基础+进阶+面试题)
linux·运维·服务器·开发语言·c++
BizzZ_3 小时前
C++(22)——类型转换和IO流
开发语言·c++
小范同学_3 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
geovindu4 小时前
CSharp: 万年历
开发语言·后端·c#·.net
我找到地球的支点啦4 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信
予昊4 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket
weixin_461408585 小时前
Mybatis-flex小记
java·开发语言·mybatis
青梅味猪大肠6 小时前
【深入浅出C++】为什么虚表指针可以解决菱形继承
开发语言·c++
潘潘的嵌入式日记6 小时前
I²C 从机接收总被覆盖?双缓冲要在 STOP 时交接
c语言·开发语言·单片机