当前位置: 首页 > news >正文

redis lua脚本(go)调用教程以及debug调试

一、GO调用核心函数

这里用go代码来展示调用,首先是核心函数介绍:

func NewScript(src string) *redisv9.Script {
func (s *Script) Load(ctx context.Context, c Scripter) *StringCmd {
func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {

第一个函数传入 lua脚本字符串,然后生成 redisv9.Script 对象
第二个函数 是通过redisv9.Script 对象的load函数 将对象存的 lua脚本字符串,传到 redis节点, 同时返回 sha,和error
第三个 redis.EvalSha 通过 sha值来确定 redis存的lua脚本,keys是传入的key值, args是参数。
keys再lua代码里是 KEYS, args在lua代码 是ARGS
直接上代码:

func TestRedisLua(t *testing.T) {InitRedis()		// 注意这个是我本地写的链接redis的函数,读者需要自己写(这里的 db.RedisCon2 就是 *redis.Client)// 这个是要执行的lua脚本luaScript = `return "keys="..KEYS[1] .. "|" ..KEYS[2].. "\nargs=" ..ARGV[1].. "|" ..ARGV[2]`redisScript := redis.NewScript(luaScript)	// 初始化脚本// 将脚本传入reids节点sha, err := redisScript.Load(context.TODO(), db.RedisCon2.GetClient()).Result()if err != nil {appzaplog.Error("redis load err", zap.Error(err))return}ret, retErr := db.RedisCon2.GetClient().EvalSha(context.Background(), sha, []string{"v1:confession_twall","v1:confession_pwall:rec:1000001",}, 1758273500, "3331").Result()if retErr != nil {appzaplog.Error("redis eval err", zap.Error(retErr))return}fmt.Println(ret.(string))
end

执行结果
在这里插入图片描述
干货:

  1. **测试用法 :**测试的时候这三个函数其实也可以用一个函数替代:
    直接传入 lua脚本字符串,key,和参数即可
func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
  1. 正式用法 NewScript 和 Load的作用是为了缓存对象,在频繁调用的时候可以显著减少 因构建对象的产生的消耗;NewScript 是go对象构建, Load是redis里的lua对象构建。

正常代码写法(伪代码)

var Sha1 = ""
// 判断 sha值是否过期
ret, err := db.RedisCon2.GetClient().ScriptExists(context.TODO(), Sha1 ).Result()
if err != nil{
...
}
if ret == false{	// sha值过期了,重新Load(redisScript 之前初始化过后,不用二次初始化)Sha1 , err = redisScript.Load(context.TODO(), db.RedisCon2.GetClient()).Result()if err != nil {appzaplog.Error("redis load err", zap.Error(err))return}
}
// 执行EvalSha操作

二、高级技巧:debug调试(linux端)

1.调试命令

 redis-cli --ldb-sync-mode  --eval  lua脚本路径  key1 key2 , 参数1 参数2redis-cli --ldb  --eval  lua脚本路径  key1 key2 , 参数1 参数2

1.1坑点讲解

  1. redis-cli --ldb-sync-mode 是阻塞的 可以断点调试,但是生产环境不要用,内网也别用(可能会被骂),最好用本地的
  2. redis-cli --ldb 不阻塞,但是这个不能断点
  3. 这个点比较离谱 逗号(,)用来区分可变参数 KEYS 和 ARGV的,但是这个逗号前后一定要空格,不要识别不了

2. 示例:
2.1构造数据
构造完成后 含 Content ReqTime的数据在最左边

redis-cli 		# 进入redis,插入数据
lpush KEYAAA 111 222 333
lpush KEYBBB 111 222 333
lpush KEYAAA {"BlackFlag":0,"RecId":1000001,"SendId":1000013,"Content":"3331","ReqTime":1758273500}
lpush KEYBBB {"BlackFlag":0,"RecId":1000001,"SendId":1000013,"Content":"3332","ReqTime":1758273500}

2.1 编写lua代码:
代码大意:搜索两个KEY中LIST元素,满足ReqTime 和 Content 和参数一致,且没有被处理过的元素。搜索到后将其删除并在最右边生成(实现右移

local function DelInfo(delKey, reqTime, content)local len = redis.call('LLEN', delKey)for i = 0, len - 1 dolocal element = redis.call('LINDEX', delKey, i)local ok, data = pcall(cjson.decode, element)if ok and type(data) == 'table' then-- 条件判断if tostring(data.ReqTime) == reqTime and data.Content == content and data.BlackFlag == 0 then-- 设置 BlackFlag = 1data.BlackFlag = 1-- 重新序列化并更新该位置元素local new_element = cjson.encode(data)redis.call('LREM', delKey, 1, element)  -- 删除原数据 (json相等的字符串绝对包含》decode后三个字段满足的元素)redis.call('RPUSH', delKey, new_element)    -- 放入最右边return data.SendIdendelsereturn 6endendreturn nil
endlocal function CallDel()local sendId = DelInfo(KEYS[1], ARGV[1], ARGV[2])if sendId == nil thenreturn 1endsendId = DelInfo(KEYS[2], ARGV[1], ARGV[2])if sendId == nil thenreturn 2endreturn 0
endreturn CallDel()

2.2 尝试执行

 redis-cli --ldb-sync-mode  --eval confess_lua.lua  KEYAAA  KEYBBB  ,  1758273500 3331c # 回车

正确的效果应该是:
含 Content ReqTime的数据在最左边,但发现KEYAAA 是正常的,但是KEYBBB没有变化(其实故意造错数据,方便用调试测试)
2.3 调试
先重新构建数据:(每次调试都执行一遍)

redis-cli 		# 进入redis,插入数据
del KEYAAA 
del KEYBBB
lpush KEYAAA 111 222 333
lpush KEYBBB 111 222 333
lpush KEYAAA {"BlackFlag":0,"RecId":1000001,"SendId":1000013,"Content":"3331","ReqTime":1758273500}
lpush KEYBBB {"BlackFlag":0,"RecId":1000001,"SendId":1000013,"Content":"3332","ReqTime":1758273500}

进入调试:

 redis-cli --ldb-sync-mode  --eval confess_lua.lua  KEYAAA  KEYBBB  ,  1758273500 3331# 下面输入 调试命令后自己加回车b 8c	   # 运行直到遇到断点p data	# 打印变量p reqTimep content	
# 最后发现 是KEYBBB 运行到 第八行的时候没有继续,打印变量发现是 content == 3331, data.Content == 3332 条件不满足

上面的调试命令应该是
加完断点输入运行(c+enter)后,遇到断点 打印 p data 和 p content,会发现第二次触发断点时打印数值发现content对不上:
在这里插入图片描述

原因是构建redis数据的时候
Content 应该是 3331 但是写成了 3332
在这里插入图片描述
所以你成功通过调试找到bug所在!!!
下面我们重新构建数据

redis-cli 		# 进入redis,插入数据
del KEYAAA 
del KEYBBB
lpush KEYAAA 111 222 333
lpush KEYBBB 111 222 333
lpush KEYAAA {"BlackFlag":0,"RecId":1000001,"SendId":1000013,"Content":"3331","ReqTime":1758273500}
lpush KEYBBB {"BlackFlag":0,"RecId":1000001,"SendId":1000013,"Content":"3331","ReqTime":1758273500}```

然后执行不阻塞命令:

 redis-cli --ldb  --eval confess_lua.lua  KEYAAA  KEYBBB  ,  1758273500 3331

查看redis数据,就发现目标数据已经右移了

调试命令大全:
当你进入调试时,输入命令 help可以看到调试命令
在这里插入图片描述

常见调试命令:
s 单步执行 进入函数
n 单步执行 不进入函数
c 继续执行直到遇到断点
b 设置断点输入数字 指定某行,输入 函数指定函数开头,输入0清除所有
l 查看当前断点前后代码
p 打印
r 执行redis命令

http://www.dtcms.com/a/469213.html

相关文章:

  • shopnc本地生活o2o网站源码有声小说网站开发
  • OpenHarmony 之Telephony电话服务技术详解:架构设计与Modem厂商库集成机制
  • 医疗AI记忆系统的分层存储机制:长期病史与短期会诊记忆的编程实现(代码部分)
  • Vue 基础认知全解析:从版本演进到生态定位
  • 苏州建网站的公司平台收费标准wordpress客户端源码分析
  • VibeCut - 智能剪辑探索与实现
  • Linux5:Linux网络编程
  • 大模型为什么会表现出逻辑性推理
  • 除了MySQL连接命令,实现自动化备份还需哪些步骤?
  • 【GD32】硬件I2C
  • 光学影像“精准导航”交叉导轨的关键作用
  • 四川省城乡住房和城乡建设厅网站注册个人订阅号
  • Linux 进程通信——基于建造者模式的信号量
  • 在Mac上安装CocoaPods问题处理
  • 深入 Spring 条件化配置底层:从硬编码到通用注解的实现原理
  • SpringBoot之配置文件
  • Linux中kmalloc内存分配函数的实现
  • 【Spring Security】Spring Security 概念
  • 杂记 12
  • 织梦程序如何搭建网站洛阳凯锦腾网业有限公司
  • Socket网络编程(2)-command_server
  • vscode 连接远程服务器同步方法
  • 传统数据安全措施与云计算数据安全的区别
  • Linux下如何在vim里使用异步编译和运行?
  • Python高效实现Excel转PDF:无Office依赖的轻量化方案
  • 做网站PPPOE网络可以吗一个好网站设计
  • 混淆矩阵在金融领域白话解说
  • 深耕金融调研领域,用科学调研破解银行服务困境(市场调研)
  • 未备案网站处理系统写作墨问题 网站
  • 【Linux】手搓日志(附源码)