一.redis中原生之行l(wèi)ua
基本命令:https://www.runoob.com/redis/redis-scripting.html
1.準(zhǔn)備一個lua腳本,test.lua
local key1 = KEYS[1]
local val1 = ARGV[1]
local key2 = KEYS[2]
local val2 = ARGV[2]
local res = redis.call("get",key1)
if (res == 18)
then
redis.call("set",key1,val1)
else
redis.call("set",key1,10)
end
return redis.call("get",key1)
如果是容器,先進(jìn)入 redis 容器之行
redis-cli -h 127.0.0.1 -p 6379 eval "$(cat test.lua)" 2 age name 15 stb
# 或者直接寫代碼也行,比如
redis-cli -h 127.0.0.1 -p 6379 eval "return {KEYS[1],ARGV[1]}" 1 name stb
如果不想每次都執(zhí)行 redis-cli,那就直接先進(jìn)入redis命令行,就可以省略redis-cli -h 127.0.0.1 -p 6379,直接執(zhí)行eval 命令,如下
redis-cli -h 127.0.0.1 -p 6379
eval "$(cat test.lua)" 1 age 15
# 或者直接寫代碼也行,比如
eval "return {KEYS[1],ARGV[1]}" 1 name stb
解釋
命令后面的 1 ,代表后面有幾個 key參數(shù),如果是 2 就是兩個參數(shù),比如上面,age和name是兩個標(biāo)識,就是 2,后面的就是對應(yīng)的內(nèi)容
golang中使用
package main
import (
"context"
"log"
"github.com/redis/go-redis/v9"
)
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
DB: 0, // 默認(rèn)DB 0
})
defer rdb.Close()
ctx := context.Background()
// 普通執(zhí)行
// 其他命令同理
// res, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"name"}, "stb").Result()
// 多行腳本執(zhí)行
res, err := rdb.Eval(ctx, `
local key1 = KEYS[1]
local key2 = KEYS[2]
local val1 = ARGV[1]
local val2 = ARGV[2]
local res = redis.call("get",key1)
if (res == 18)
then
redis.call("set",key1,val1)
else
redis.call("set",key1,10)
end
return redis.call("get",key2)
`, []string{"name", "age"}, "stb", 18).Result()
if err != nil {
return
}
log.Println("res=:", res)
}
解釋:
其實(shí)就是 lua 的代碼,在redis 中用對應(yīng)的命令去執(zhí)行,比如 eval,把lua 代碼看成一段字符串,然后用redis eval 命令執(zhí)行,加上對應(yīng)的參數(shù)即可
問題解析
1.執(zhí)行錯誤會繼續(xù)執(zhí)行
2.eval每次都會將完整的腳本傳遞,網(wǎng)絡(luò)開銷大,應(yīng)該先用script load 預(yù)先緩存,然后用反饋的 哈嘻值,使用 evalsha來執(zhí)行
// 輸入該腳本
# redis-cli script load "$(cat test.lua)"
"bdb8680ea6967110d89ea6e574b6cf4b2b3e6507" // 這個用來執(zhí)行的標(biāo)識
// 執(zhí)行該腳本
# redis-cli evalsha bdb8680ea6967110d89ea6e574b6cf4b2b3e6507 2 age name 15 17
(integer) 32 // 反饋結(jié)果