文章目录
使用背景
lua 脚本
所有操作封装到一起,依次执行,整个操作是原子性,不会被其它中断。
批量执行脚本
语法介绍
输出字符串
EVAL "return 'Hello'" 0
有参数
redis> EVAL "return ARGV[1]" 0 Hello
"Hello"
redis> EVAL "return ARGV[1]" 0 Parameterization!
"Parameterization!"
执行redis函数
1 代表key的参数个数
foo key
bar value
相当于set foo bar
> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
缓存脚本
想当于把脚本缓存到客户端,这样能够减少每次执行时传输的数据量
SCRIPT LOAD 加载
EVALSHA 执行脚本
redis> SCRIPT LOAD "return 'Immabe a cached script'"
"c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f"
redis> EVALSHA c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f 0
"Immabe a cached script"
清除脚本
把服务器的缓存脚本清除
SCRIPT FLUSH c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f
场景
更新json 对象
SET mykey '{"name": "原始名字", "age": 30}'
-- Lua 脚本开始
local json = require 'cjson' -- 确保 cjson 库可用
-- 查询 JSON 数据
local data = redis.call('GET', 'mykey')
if data then
-- 解析 JSON 数据
local jsonData = json.decode(data)
-- 修改数据
jsonData.name = '新的名字' -- 修改字段
-- 将修改后的数据编码为 JSON 字符串
local newData = json.encode(jsonData)
-- 更新到 Redis
redis.call('SET', 'mykey', newData)
return '数据更新成功'
else
return '没有找到数据'
end
-- Lua 脚本结束
实现计数器
-- Lua 脚本开始
local counter_key = KEYS[1] -- 计数器的键
local threshold = tonumber(ARGV[1]) -- 阈值
-- 获取当前计数
local current_count = tonumber(redis.call('GET', counter_key) or 0)
-- 增加计数
current_count = current_count + 1
-- 检查是否达到阈值
if current_count >= threshold then
current_count = 0 -- 重置计数
end
-- 更新计数到 Redis
redis.call('SET', counter_key, current_count)
return current_count
-- Lua 脚本结束
spring 和lua 结合
lua 脚本定义
-- Lua 脚本
local user_ids = cjson.decode(ARGV[1]) -- 从参数中获取用户 IDs
local age_increment = tonumber(ARGV[2]) -- 从参数中获取年龄增量
local updated_users = {}
for _, user_id in ipairs(user_ids) do
local user_key = 'user:' .. user_id
local user_data = redis.call('HGETALL', user_key)
if #user_data > 0 then
local user_info = {}
for i = 1, #user_data, 2 do
user_info[user_data[i]] = user_data[i + 1]
end
-- 更新年龄
local current_age = tonumber(user_info['age']) or 0
user_info['age'] = current_age + age_increment
-- 更新到 Redis
redis.call('HMSET', user_key, 'name', user_info['name'], 'age', user_info['age'])
table.insert(updated_users, user_info)
end
end
return cjson.encode(updated_users)
spring 代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Service
public class UserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public List<Object> updateUserAges(List<String> userIds, int ageIncrement) {
String script = loadLuaScript("scripts/updateUser.lua");
return (List<Object>) redisTemplate.execute(
new DefaultRedisScript<>(script, List.class),
Collections.emptyList(),
JsonUtils.toJson(userIds), // 将 List 转换为 JSON 字符串
ageIncrement
);
}
private String loadLuaScript(String path) {
// 从文件加载 Lua 脚本
try {
return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("Failed to load Lua script", e);
}
}
}