赞
踩
本文主要介绍我们为什么使用redis脚本,如何正确去使用,怎么保证原子性,具体的应用场景
Redis脚本使用 Lua 解释器来执行,所以我们一般叫Lua脚本
Redis 2.6 版本通过内嵌支持 Lua 环境
执行脚本的命令是 EVAL,基本语法如下:
EVAL script numkeys key [key …] arg [arg …]
在 Lua 脚本中,可以使用两个不同函数来执行 Redis 命令,它们分别是:redis.call()和redis.pcall()
两者的区别在于它们对错误处理的不同
我们通过编写两段脚本,来执行下,并验证不同函数
准备测试数据
本地:0>set key1 1
"OK"
本地:0>set key2 2
"OK"
本地:0>set forlan 程序员
"OK"
编写lua脚本,把key1、key2对应的值分别从1、2改成11、22
本地:0>eval "redis.call('SET',KEYS[1],ARGV[1]); redis.call('HGET','forlan',ARGV[1]); redis.call('SET',KEYS[2],ARGV[2]);return 1;" 2 key1 key2 11 22
"ERR Error running script (call to f_50eb1c8e04a6356bc813ba70dad327b5be4b0c0c): @user_script:1: WRONGTYPE Operation against a key holding the wrong kind of value "
本地:0>get key1
"11"
本地:0>get key2
"2"
本地:0>eval "redis.pcall('SET',KEYS[1],ARGV[1]); redis.pcall('HGET','forlan',ARGV[1]); redis.pcall('SET',KEYS[2],ARGV[2]);return 1;" 2 key1 key2 11 22
"1"
本地:0>get key1
"11"
本地:0>get key2
"22"
我们通过redis.call(‘HGET’,‘forlan’,ARGV[1]);来模拟出错的情况
redis.call()函数会中断Lua脚本的执行,并抛出异常;
redis.pcall()函数不会中断Lua脚本的执行;
所以,为了保证脚本的原子性,要谨慎使用redis.call()函数,我们在代码中使用的话,记得需要捕获异常处理
官方解答
Atomicity of scripts
Redis uses the same Lua interpreter to run all the commands. Also Redis guarantees that a script is executed in an atomic way: no other script or Redis command will be executed while a script is being executed. This semantic is similar to the one of MULTI / EXEC- From the point of view of all the other clients the effects of a script are either still not visible or already completed
中文意思
Redis使用相同的Lua解释器来运行所有命令。此外,Redis保证脚本以原子方式执行:在执行脚本时,不会执行其他脚本或Redis命令。这个语义类似于MULTI/EXEC的语义-从所有其他客户端的角度来看,脚本的效果要么仍然不可见,要么已经完成
简单理解,就是执行脚本时不会执行其他脚本或Redis命令,类似于给脚本加了锁
虽然脚本的开销很小,但我们使用的时候,注意避免使用慢脚本,以免脚本执行的时候,我们其它redis命令无法执行
本地:0>eval " local key = KEYS[1] local id = redis.call('get',key) if(id == false) then redis.call('set',key,1) return 1 else redis.call('set',key,id+1) return id end" 1 forlan
"1"
本地:0>eval " local key = KEYS[1] local id = redis.call('get',key) if(id == false) then redis.call('set',key,1) return 1 else redis.call('set',key,id+1) return id end" 1 forlan
"2"
本地:0>eval " local key = KEYS[1] local id = redis.call('get',key) if(id == false) then redis.call('set',key,1) return 1 else redis.call('set',key,id+1) return id end" 1 forlan
"3"
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。