Jedis与Lua脚本结合
2、原子性的操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。
3、代码复用:客户端发送的脚步会永久存在redis中,这样,其他客户端可以复用这一脚本来完成相同的逻辑。
4、速度快:见 与其它语言的性能比较, 还有一个 JIT编译器可以显著地提高多数任务的性能; 对于那些仍然对性能不满意的人, 可以把关键部分使用C实现, 然后与其集成, 这样还可以享受其它方面的好处。
5、可以移植:只要是有ANSI C 编译器的平台都可以编译,你可以看到它可以在几乎所有的平台上运行:从 Windows 到Linux,同样Mac平台也没问题, 再到移动平台、游戏主机,甚至浏览器也可以完美使用 (翻译成JavaScript).
6、源码小巧:20000行C代码,可以编译进182K的可执行文件,加载快,运行快。


一般java运行lua脚本,采用的也是类似上述表达式,后面描述
(2)对于一段长的lua脚本,可以将脚本放在一个文件中,通过如下命令执行lua脚本
$ redis-cli --eval path/to/redis.lua KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...
--eval,告诉redis-cli读取并运行后面的lua脚本
path/to/redis.lua,是lua脚本的位置
KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。
注意: KEYS和ARGV中间的 ',' 两边的空格,不能省略。
看下面例子:
在如下文件夹中以一个lua脚本 jedisCallLuaTest.lua

local key=KEYS[]
local args=ARGV
//说明:设置一个key = userName,value=Jack,20s过期时间
return redis.call("setex",key,unpack(args))

去客户端获取:

过期了。。。。
EVALSHA命令
将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。
语法如下:
redis 127.0.0.1:6379> EVALSHA sha1 numkeys key [key ...] arg [arg ...]
参数说明:
- sha1 : 通过 SCRIPT LOAD 生成的 sha1 校验码。
- numkeys: 用于指定键名参数的个数。
- key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
- arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
eg:

整合Jedis + lua
(1)Jedis的使用
public class RedisClient {
private static JedisPool jedisPool = null;
private static String addr = "127.0.0.1";
private static int port = 6379;
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
// 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
config.setBlockWhenExhausted(true);
// 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最 大空闲连接数)
config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");
// 是否启用pool的jmx管理功能, 默认true
config.setJmxEnabled(true);
// MBean ObjectName = new
// ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name="
// + "pool" + i); 默认为"pool", JMX不熟,具体不知道是干啥的...默认就好.
config.setJmxNamePrefix("pool");
// 是否启用后进先出, 默认true
config.setLifo(true);
// 最大空闲连接数, 默认8个
config.setMaxIdle(8);
// 最大连接数, 默认8个
config.setMaxTotal(8);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,
// 默认-1
config.setMaxWaitMillis(-1);
// 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
config.setMinEvictableIdleTimeMillis(1800000);
// 最小空闲连接数, 默认0
config.setMinIdle(0);
// 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
config.setNumTestsPerEvictionRun(3);
// 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数
// 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
config.setSoftMinEvictableIdleTimeMillis(1800000);
// 在获取连接的时候检查有效性, 默认false
config.setTestOnBorrow(false);
// 在空闲时检查有效性, 默认false
config.setTestWhileIdle(false);
// 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
config.setTimeBetweenEvictionRunsMillis(-1);
jedisPool = new JedisPool(config, addr, port, 3000);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void close(final Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
/*---------------------测试---------------------------*/
public static void main(java.lang.String[] args) {
Jedis jedis = RedisClient.getJedis();
// do something
RedisClient.testCallLua(jedis);
RedisClient.close(jedis);
}
public static void testCallLua(Jedis jedis){
String luaStr = "return {KEYS[1],KEYS[1],ARGV[1],ARGV[2]}";
Object result = jedis.eval(luaStr, Lists.newArrayList("userName","age"), Lists.newArrayList("Jack","20"));
System.out.println(result);
}
}
运行结果:
[userName, userName, Jack, 20]
java: 该段代码图个方便,引用了guava.jar包
/**
* 调用lua脚本
* @param jedis
*/
public static void testCallLuaFile(Jedis jedis){
String luaStr = null;
//带反斜杠,路径为classPath,不带反斜杠,路径为类的同一目录
Reader r = new InputStreamReader(RedisClient.class.getResourceAsStream("/jedisCallLuaTest.lua"));
try {
luaStr = CharStreams.toString(r);
Object result = jedis.eval(luaStr, Lists.newArrayList("userName"), Lists.newArrayList("20","Tom"));
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
注意:getResourceAsStream()这可是好帮手,用到将文件内容加载成String,一定要想到他。CharStreams是guava.jar中的对象。
Reader转String还有如下两种伎俩:(发散。。。。)
@Test
public void apcheIo() throws IOException{
String luaStr=null;
//带反斜杠,路径为classPath,不带反斜杠,路径为类的同一目录
Reader r= new InputStreamReader(Reader2StrDemo.class.getResourceAsStream("/jedisCallLuaTest.lua")); luaStr = org.apache.commons.io.IOUtils.toString(r);
System.out.println(luaStr);
} @Test
public void java8() throws IOException{
String luaStr=null;
String path = "F:\\xxxx\\ideaProjects\\java8-pro\\resource\\jedisCallLuaTest.lua"; luaStr = Files.lines(Paths.get(path),Charset.defaultCharset()).collect(Collectors.joining());
System.out.println(luaStr);
}
运行结果:

Jedis与Lua脚本结合的更多相关文章
- 使用jedis执行lua脚本
转: redis学习(十五) 使用jedis执行lua脚本(实现一个对IP的限流) 2018年09月15日 20:07:26 码农-文若书生 阅读数:1609 使用jedis执行lua脚本(实现一 ...
- 用Jedis调用Lua脚本来完成redis的数据操作
1.先完成一个简单的set/get操作 package com.example.HnadleTaskQueue; import redis.clients.jedis.Jedis; import ja ...
- redisTemplate的spring配置以及lua脚本驱动
最近在使用spring-data-redis的redisTemplate,所以写篇使用记录吧. 1.不用多说,使用maven引入相关依赖,因为项目已经引入其他的 <dependency> ...
- redis使用Lua脚本
最近在看<Redis入门指南>第二版,感觉收获挺大,推荐大家有时间看一看.其中有一章讲Lua脚本,感觉挺实用,把总结整理一下. Redis在2.6中推出了脚本功能,允许开发者使用Lua语言 ...
- Lua脚本在redis分布式锁场景的运用
目录 锁和分布式锁 锁是什么? 为什么需要锁? Java中的锁 分布式锁 redis 如何实现加锁 锁超时 retry redis 如何释放锁 不该释放的锁 通过Lua脚本实现锁释放 用redis做分 ...
- Redis结合Lua脚本实现高并发原子性操作
从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis … 案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次. 非脚 ...
- 在redis中使用lua脚本
在实际工作过程中,可以使用lua脚本来解决一些需要保证原子性的问题,而且lua脚本可以缓存在redis服务器上,势必会增加性能. 不过lua也会有很多限制,在使用的时候要注意. 在Redis中执行Lu ...
- Lua脚本语言快速入门手册
学了两天Lua语言,感叹其短小精悍,上手极快,语法还很舒服,不错!整理下学习过程中经常用到的基础知识,共勉! Lua用法简述 Lua语言是在1993年由巴西一个大学研究小组发明,其设计目标是作为嵌入式 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[四]--基于Redis lua脚本机制实现分布式锁
一.redis lua介绍 Redis 提供了非常丰富的指令集,但是用户依然不满足,希望可以自定义扩充若干指令来完成一些特定领域的问题.Redis 为这样的用户场景提供了 lua 脚本支持,用户可以向 ...
随机推荐
- python简说(二十二)写日志
分四个级别 import nnloglog = nnlog.Logger('book_server.log') log.debug('xxx值是什么')log.info('调用了什么xxx')log. ...
- CEF 文件下载
转载:https://blog.csdn.net/liuyan20092009/article/details/53819473?locationNum=6&fps=1 转载:https:// ...
- C语言动态链表数据结构
链表的操作增删改查 typedef int DATA; struct SNode { DATA data; SNode* pNext; }; SNode* g_head=NULL;//全局变量 //从 ...
- (转)能根据文字生成图片的 GAN,深度学习领域的又一新星
本文转自:https://mp.weixin.qq.com/s?__biz=MzIwMTgwNjgyOQ==&mid=2247484846&idx=1&sn=c2333a998 ...
- webpack用 babel将ES6转译ES5
webpack webpack.config.js配置文件 module.exports = { entry: './es6.js', // 入口文件路径 output: { filename: &q ...
- Apple ID双重认证验证码无法输入问题
问题:用Apple ID登录老版本ios系统时,会提示“”需要提供Apple ID验证码才能登陆.请键入您的密码,并随后键入显示在您其他设备上的验证码”. 解决:老版本系统无输入验证码的地方,那就把验 ...
- Unity3D学习笔记(三十六):Shader着色器(3)- 光照
光照模型:用数学的方法模拟现实世界中的光照效果. 场景中模型身上的光反射到相机中的光线: 1.漫反射:产生明暗效果 2.高光反射:产生镜面反射,物体中有最亮且比较耀眼的一部分 3.自发光: 4.环 ...
- Twitter开发2
There are different API families The standard (free) Twitter APIs consist of REST APIs and Streaming ...
- 17秋 SDN课程 第一次上机作业
第一题 拓扑: 测试连通性: 第二题 拓扑: 测试连通性: 第三题 拓扑: 测试连通性:
- window下的Django入门
一.window下新建安装(参考书籍:<python编程:从入门到实践>) 新建一个文件夹 learning_log ,在终端中切换到该目录下,并创建一个虚拟工作环境,运行模块 venv ...