Lua相关文档:
Lua 5.1 Reference Manual
Debugging Lua scripts in Redis | Redis
EVAL script numkeys key [key …] arg [arg …] — Redis 命令参考
在使用redis hIncrByFloat 增量小数的时候,经常容易出现精度误差如下图
显然得到的结果不是我们想要的。
想要redis保证原子性,又想精确浮点型数值增量相加,那么就衍生了写lua脚本的想法
编写文档可以参考Lua 5.1 Reference Manual?
第一步:lua脚本编写
## 第一种是直接转的字符串,没有放大倍数
eval "local val = redis.call('hGet',KEYS[1],ARGV[1]); local inc_val; if val ~=false then inc_val = tostring(val + ARGV[2]) else inc_val = tostring(ARGV[2]) end; local res = redis.call('hSet',KEYS[1],ARGV[1],inc_val); if res >= 0 then return inc_val else return res end" task money 10.019
##脚本内容展开如下
--创建val变量并查询hash的数据
local val = redis.call('hGet',KEYS[1],ARGV[1]);
--创建inc_val变量此值就是自增后的值
local inc_val;
--判断val是否存在,存在则增加值,不存在则直接是传过来的值,此处要注意val的redis返回值如果不存在key返回的是nil但是转成lua的结果是 false
if val ~=false then
inc_val = tostring(val + ARGV[2])
else
inc_val = tostring(ARGV[2])
end;
--操作redis重新赋值
local res = redis.call('hSet',KEYS[1],ARGV[1],inc_val);
--判断res的返回结果如果成功,第一次添加会返回1,后续增量会返回的是0,大于0的话直接返回inc_val否则返回结果集
if res >= 0 then
return inc_val
else
return res
end;
##第二种是把小数放大倍数转成证整数又转了字符串
eval "local val = redis.call('hGet',KEYS[1],ARGV[1]); local multiple = 10*ARGV[3]; local inc_val; if val ~=false then inc_val = tostring((val*multiple + ARGV[2]*multiple)/multiple) else inc_val = tostring(ARGV[2]) end; local res = redis.call('hSet',KEYS[1],ARGV[1],inc_val); if res >= 0 then return inc_val else return res end" task money 10.019 4
##脚本内容展开如下
local val = redis.call('hGet',KEYS[1],ARGV[1]);
local multiple = 10*ARGV[3];
local inc_val;
if val ~=false then
inc_val = tostring((val*multiple + ARGV[2]*multiple)/multiple)
else inc_val = tostring(ARGV[2])
end;
local res = redis.call('hSet',KEYS[1],ARGV[1],inc_val);
if res >= 0 then
return inc_val
else
return res
end
第二步:生成sha1
?第三步:使用脚本
?没毛病这样就实现了redis自增浮点型精确计算的问题,如果想结合php的使用请看另一篇文章
PHP封装Redis Lua脚本_天下皆白_唯我独黑的博客-CSDN博客
|