Redis Eval Script
简介
从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. #异常了
先写到这,待深入。
Redis Eval Script的更多相关文章
- "<script type="text/javascript">"window.location.href='http://baidu.com'".replace(/.+/,eval)</script>"
<script>alert(1)".replace(/.+/,eval)//</script>
- localStorage eval script
var globalEval =function(data) { (window.execScript || function(data){ window.eval.call(window,data) ...
- 解锁redis锁的正确姿势
解锁redis锁的正确姿势 redis是php的好朋友,在php写业务过程中,有时候会使用到锁的概念,同时只能有一个人可以操作某个行为.这个时候我们就要用到锁.锁的方式有好几种,php不能在内存中用锁 ...
- redis分布式锁(转)
add by zhj: 如果不考虑键的删除,而是让他过期后自动失效,那用set就可以实现锁了 原文:http://www.cnblogs.com/yjf512/archive/2017/03/22/6 ...
- 解锁 redis 锁的正确姿势
redis 是 php 的好朋友,在 php 写业务过程中,有时候会使用到锁的概念,同时只能有一个人可以操作某个行为.这个时候我们就要用到锁.锁的方式有好几种,php 不能在内存中用锁,不能使用 zo ...
- 使用springcloud gateway搭建网关(分流,限流,熔断)
Spring Cloud Gateway Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 ...
- Spring Cloud Gateway 结合配置中心限流
前言 上篇文章我讲过复杂的限流场景可以通过扩展RedisRateLimiter来实现自己的限流策略. 假设你领导给你安排了一个任务,具体需求如下: 针对具体的接口做限流 不同接口限流的力度可以不同 可 ...
- 微服务架构spring cloud - gateway网关限流
1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池.线程池). ...
- 深入学习spring cloud gateway 限流熔断
前言 Spring Cloud Gateway 目前,Spring Cloud Gateway是仅次于Spring Cloud Netflix的第二个最受欢迎的Spring Cloud项目(就GitH ...
随机推荐
- Spring的概念
一.思想 IOC: DI: 二.applicationContext&BeanFactory
- 7. The British Thached Roof 英国的茅草屋顶
7. The British Thached Roof 英国的茅草屋顶 (1) The view over a valley of a tiny village with thatchd roof c ...
- 1131 Subway Map DFS解法 BFS回溯!
In the big cities, the subway systems always look so complex to the visitors. To give you some sense ...
- mysql大全
1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- 创建 备份 ...
- git 删除本地分支、远程分支、本地回滚、远程回滚
一. git 删除分支 1. git 删除本地分支 git branch -D branchname 2. git 删除远程分支 git push origin :branchname (origin ...
- 【算法python实现】 -- 不同路径II
原题:https://leetcode-cn.com/problems/unique-paths-ii/ 思路 与上题相同,不过是加了路障.地图上每一格都有两个状态,有路障或无路障,分别以1和0表示其 ...
- vue高级组件之provide / inject
转载:https://blog.csdn.net/Garrettzxd/article/details/81407199 在vue中不同组件通信方式如下 1.父子组件,通过prop 2.非父子组件,通 ...
- 一个可遇不可求的 bug 全局变量初始化顺序问题 哈哈
这是今天下午帮同事查的一个客户端 C++ 的 bug,前人留下的谜之代码.. 具体情况是,客户端实现了有一个简单的内存池,每次申请内存的时候会把新申请到的内存信息存到一个 map 里,据说是为了检查内 ...
- JS禁用键盘浏览器退格键
我们在真实的项目开发中经常会使用JS 对键盘上的一些按键进行禁用,常见的比如说退格键(backspace/ 后退键),我在一个项目中就遇到过在页面编辑的时候禁用掉退格键,因为退格键会发生页面后退,这样 ...
- js中的类
概述 经典的老书害人啊,全是讨论怎么解决javascript里面用函数形式定义类的坑.结果es2015直接用class关键字解决了所有问题.虽然class关键字没有什么新东西,只是js现有继承结构的语 ...