Redis Eval Script


簡介

從Redis 2.6 版本開始,內嵌支持 Lua 環境。通過使用EVALEVALSHA命令可以使用 Lua 解釋器來執行腳本。 EVAL和EVALSHA的使用是差不多的(下面有講區別)。

EVAL命令

語法: EVAL script numkeys key [key ...] arg [arg ...] 。

script:Lua腳本 。numkeys:key的參數個數。訪問腳本獲取key值:KEYS[1], KEYS[2], ... (KEYS必須大寫),獲取arg值:ARGV[1], ARGV[2], ...(ARGV必須大寫)。

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],ARGV[2]}" 1 1 ONE TWO
1) "1"
2) "ONE"
3) "TWO"

在Lua腳本中可以通過使用redis.call()或redis.pcall()函數調用redis命令。

127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> eval "return redis.call('set','foo','bibi')" 0
OK
127.0.0.1:6379> get foo
"bibi"
127.0.0.1:6379> eval "return redis.call('set',KEYS[1],'bar')" 1 foo
OK

 至於redis.call(),redis.pcall()的不同,在於錯誤提示不一樣

127.0.0.1:6379>  eval "return redis.call('setset','yyyy','oo')" 0
(error) ERR Error running script (call to f_9b37f897c55c73737f181184c9781281dc9b45e3): @user_script:1: @user_script: 1: Unknown Redis command called from Lua script
127.0.0.1:6379>  eval "return redis.pcall('setset','yyyy','oo')" 0
(error) @user_script: 1: Unknown Redis command called from Lua script
127.0.0.1:6379>

Redis與Lua數據類型的轉換

在Lua腳本通過redis.call()或redis.pcall()執行redis命令,發生數據類型轉換:redis命令返回值--------------->lua數據類型。

Lua腳本在Redis內嵌的解釋器運行,發生數據類型珠海:lua數據類型-------------->redis命令返回值。

Lua數據類型轉Redis類型

  • Lua number  -> Redis integer reply (the number is converted into an integer)
    127.0.0.1:6379> eval "return 9" 0
    (integer) 9
  • Lua string -> Redis bulk reply  bulk類型支持多種數據類型批量返回
    127.0.0.1:6379> eval "return 'hengheng'" 0
    "hengheng"
  • Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)
    127.0.0.1:6379> eval "return{'3','rr',4}" 0
    1) "3"
    2) "rr"
    3) (integer) 4
  • Lua table with a single ok field -> Redis status reply ,status類型就是很隨意的狀態
    127.0.0.1:6379> eval "return {ok='oppp'}" 0
    oppp
  • Lua table with a single err field -> Redis error reply  ,error類型,前面帶有括號(error)注明是error類型,區分status類型
    127.0.0.1:6379>  eval "return {err='eeeeeeeeeeee'}" 0
    (error) eeeeeeeeeeee
    127.0.0.1:6379> eval "return {ok='ooooooooooooooo'}" 0
    ooooooooooooooo
  • Lua boolean false -> Redis Nil bulk reply.
    127.0.0.1:6379> eval "return false" 0   
    (nil)

Redis數據類型轉lua數據類型:

  • Redis integer reply -> Lua number
  • Redis bulk reply -> Lua string
  • Redis multi bulk reply -> Lua table (may have other Redis data types nested)
  • Redis status reply -> Lua table with a single ok field containing the status
  • Redis error reply -> Lua table with a single err field containing the error
  • Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type

Redis數據類型和lua數據類型並不完全對應:

Lua的編號如果非整數,應作為字符串返回,因為總是轉為Redis整數類型

127.0.0.1:6379> eval "return 90.4231" 0
(integer) 90
在Lua數組中使用nils,會停止轉換直到數組的最后。

127.0.0.1:6379> eval "return {2332,'rrr','fff',nil,'gg'}"  0
1) (integer) 2332
2) "rrr"
3) "fff"      

運行Lua腳本的原子性

Redis使用Lua解釋器解釋Lua腳本過程中,會保證腳本是以原子性的方式執行,也就是腳本的效果要么仍然不可見,要么已經完成既然是原子性,那當腳本還沒運行完時,其他客戶端是無法執行命令的。

所以,該腳本就別搞那么復雜吧,當然,看清況,該復雜也沒轍。

EVAL和EVALSHA區別

Eval執行的腳本不從緩存里拿,而Evalsha執行的腳本從緩存拿,跟sha1校驗碼從服務器緩存里拿。(sha1就好像身份證)

命令:EVALSHA sha1 numkeys key [key ...] arg [arg ...]

127.0.0.1:6379> script load "return 5"    #往緩存里加入腳本 , 返回sha1校驗碼 
"4ca238f611c9d0ae4e9a75a5dbac22aedc379801"
127.0.0.1:6379> script exists 4ca238f611c9d0ae4e9a75a5dbac22aedc379801 #是否存在某腳本  
1) (integer) 1
127.0.0.1:6379> evalsha 4ca238f611c9d0ae4e9a75a5dbac22aedc379801 0 #執行腳本
(integer) 5
127.0.0.1:6379> script flush
OK
127.0.0.1:6379> script exists 4ca238f611c9d0ae4e9a75a5dbac22aedc379801 
1) (integer) 0     #0表示不存在了
127.0.0.1:6379>  evalsha 4ca238f611c9d0ae4e9a75a5dbac22aedc379801 0
(error) NOSCRIPT No matching script. Please use EVAL.  #異常了

 

先寫到這,待深入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM