1.lua简介
从Redis 2.6.0版本开始,通过内置的左上臂解释器,可以使用评价评价命令对左上臂脚本进行求值。使用心得使用单个左上臂解释器去运行所有脚本,并且使用心得也保证脚本会以原子性(原子)的方式执
行:当某个脚本正在运行的时候,不会有其他脚本或使用心得命令被执行。这和使用多重/执行包
围的事务很类似。在其他别的客户端看来,脚本的效果(效果)要么是不可见的(不可见),要么就是
已完成的(已经完成).
2.Lua脚本配置流程
在资源目录下面新增一个后缀名为。左上臂结尾的文件编写脚本执行内容
调用redisTemplate.execute方法执行脚本
3.lua eval:http://doc.redisfans.com/script/eval.html
4.本地起两个服务节点作为演示。演示代码如下:
本文采用定时调度模拟线程去获取锁(链接:详解预定的定时调度)使用-Dserver.port=9527,-Dserver.port=9528开启多个节点
本地lock_key=KEYS[1]
本地lock_value=KEYS[2]
本地结果=redis.call('SETNX ',lock_key,lock_value)
如果结果==1
然后
redis.call('SETEX ',lock_key,60,lock_value)
回送结果
其他
回送结果
目标
左上臂脚本存储客户端执行命令如下:
redis-cli - eval xxxx.lua值值.
ps:执行成功返回1,失败返回0
本地lock_key=KEYS[1]
本地lock_value=KEYS[2]
本地lock_time_out=KEYS[3]
本地结果=redis.call('SET ',lock_key,lock_value,' EX ',lock_time_out,' NX ')
回送结果
ps:执行成功返回好的,失败返回无
@组件
公共类RedisLock {
@自动连线
私有重新模板重新模板
私有defaultrediscriptboolean Lockscript;
@Value('${server.port} ')
私有字符串端口;
@Scheduled(cron='0/5 * * * * * ')
公共无效锁(){ 0
字符串锁=' LockNxExJob
布尔无=假;
尝试{
//获取锁
缺席=luaExpress(锁,端口);
if(!缺席)
系统。出去。println(字符串。格式('获取锁失败!被%s拿走,redisTemplate.opsForValue().get(lock)));
} else {
系统。出去。println(字符串。格式('获取锁成功!值为:%s ',redisTemplate.opsForValue().get(lock)));
}
}捕获(例外e){ 0
e。print stack trace();
}最后{
//释放锁
如果(缺席)redisTemplate.delete(锁定);
}
}
公共布尔luaExpress(字符串键,字符串值){ 0
lockScript=new defaultredscript();
锁定脚本。setscriptsource(新资源scriptsource(新类路径资源(' Lua redis。Lua ')));
lockScript.setResultType(布尔值。类);
ListObject list=new ArrayList();
名单。add(键);
名单。添加(值);
布尔结果=(布尔)redistemplate。执行(lockScript,list);
返回结果;
}
}
ps:当节点9527成功获取分布式锁,在没有执行释放锁之前,服务节点宕掉了,节点9528则会无法获取到锁,直到设置锁的超时时间结束,才能获得锁。避免了单节点挂掉了,锁一直未被释放的尴尬场景。
5.总结
Redis使用单个左上臂解释器去运行所有脚本,并且使用心得也保证脚本会以原子性(原子)的方式执行:当某个脚本正在运行的时候,不会有其他脚本或使用心得命令被执行,保证了只要能setnx成功就能setex。解决了服务获取锁成功,但突然宕机,未能设置超时时间问题。