簡介
從Redis 2.6 版本開始,內嵌支持 Lua 環境。通過使用EVAL或EVALSHA命令可以使用 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. #異常了
先寫到這,待深入。