一、GO调用核心函数
这里用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
直接上代码:
            
            
              go
              
              
            
          
          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
        执行结果

干货:
- **测试用法 :**测试的时候这三个函数其实也可以用一个函数替代:
直接传入 lua脚本字符串,key,和参数即可 
            
            
              go
              
              
            
          
          func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
        - 正式用法 NewScript 和 Load的作用是为了缓存对象,在频繁调用的时候可以显著减少 因构建对象的产生的消耗;NewScript 是go对象构建, Load是redis里的lua对象构建。
 
正常代码写法(伪代码)
            
            
              go
              
              
            
          
          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.调试命令
            
            
              go
              
              
            
          
           redis-cli --ldb-sync-mode  --eval  lua脚本路径  key1 key2 , 参数1 参数2
 redis-cli --ldb  --eval  lua脚本路径  key1 key2 , 参数1 参数2
        1.1坑点讲解
- redis-cli --ldb-sync-mode 是阻塞的 可以断点调试,但是生产环境不要用,内网也别用(可能会被骂),最好用本地的
 - redis-cli --ldb 不阻塞,但是这个不能断点
 - 这个点比较离谱 逗号(,)用来区分可变参数 KEYS 和 ARGV的,但是这个逗号前后一定要空格,不要识别不了
 
2. 示例:
2.1构造数据
构造完成后 含 Content ReqTime的数据在最左边
            
            
              bash
              
              
            
          
          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 和参数一致,且没有被处理过的元素。搜索到后将其删除并在最右边生成(实现右移)
            
            
              lua
              
              
            
          
          local function DelInfo(delKey, reqTime, content)
    local len = redis.call('LLEN', delKey)
    for i = 0, len - 1 do
        local 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 = 1
                data.BlackFlag = 1
                -- 重新序列化并更新该位置元素
                local new_element = cjson.encode(data)
                redis.call('LREM', delKey, 1, element)  -- 删除原数据 (json相等的字符串绝对包含》decode后三个字段满足的元素)
                redis.call('RPUSH', delKey, new_element)    -- 放入最右边
                return data.SendId
            end
        else
            return 6
        end
    end
    return nil
end
local function CallDel()
    local sendId = DelInfo(KEYS[1], ARGV[1], ARGV[2])
    if sendId == nil then
        return 1
    end
    sendId = DelInfo(KEYS[2], ARGV[1], ARGV[2])
    if sendId == nil then
        return 2
    end
    return 0
end
return CallDel()
        2.2 尝试执行
            
            
              bash
              
              
            
          
           redis-cli --ldb-sync-mode  --eval confess_lua.lua  KEYAAA  KEYBBB  ,  1758273500 3331
 c # 回车
        正确的效果应该是:
含 Content ReqTime的数据在最左边 ,但发现KEYAAA 是正常的,但是KEYBBB没有变化(其实故意造错数据,方便用调试测试)
2.3 调试
先重新构建数据:(每次调试都执行一遍)
            
            
              bash
              
              
            
          
          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}
        进入调试:
            
            
              bash
              
              
            
          
           redis-cli --ldb-sync-mode  --eval confess_lua.lua  KEYAAA  KEYBBB  ,  1758273500 3331
 # 下面输入 调试命令后自己加回车
 b 8
 c	   # 运行直到遇到断点
 p data	# 打印变量
 p reqTime
 p content	
# 最后发现 是KEYBBB 运行到 第八行的时候没有继续,打印变量发现是 content == 3331, data.Content == 3332 条件不满足
        上面的调试命令应该是
加完断点输入运行(c+enter)后,遇到断点 打印 p data 和 p content,会发现第二次触发断点时打印数值发现content对不上:

原因是构建redis数据的时候
Content 应该是 3331 但是写成了 3332

所以你成功通过调试找到bug所在!!!
下面我们重新构建数据
            
            
              go
              
              
            
          
          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}```
        然后执行不阻塞命令:
            
            
              bash
              
              
            
          
           redis-cli --ldb  --eval confess_lua.lua  KEYAAA  KEYBBB  ,  1758273500 3331
        查看redis数据,就发现目标数据已经右移了
调试命令大全:
当你进入调试时,输入命令 help可以看到调试命令

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