1.为什么要实现lua脚本
redis单一命令可以保证原子性,但是多个命令组合起来就不能保证原子性。比如先incry后
expire,incry命令是不能设置key的过期时间的,但是在工作中经常会设置incry key的过期时间,但是要保证原子性,所以引入lua脚本,同时lua脚本也可以实现分布式锁。
2.实践中遇到的坑
先贴代码
public Long incrEx(String key, Long defaultExpire){ final String script = "local visitNum = redis.call('incr', KEYS[1])" + "if visitNum == 1 then " + " redis.call('expire', KEYS[1], ARGV[1])" + "end " + "return visitNum;"; // 指定 lua 脚本,并且指定返回值类型 DefaultRedisScript redisScript = new DefaultRedisScript<>(); redisScript.setResultType(Long.class); redisScript.setScriptText(script); RedisSerializer<String> stringRedisSerializer = redisTemplate.getStringSerializer(); List<String> keys = new ArrayList<>(); keys.add(key); // 参数一:redisScript,参数二:key列表,参数三:arg(可多个) Object result = redisTemplate.execute(redisScript, stringRedisSerializer, stringRedisSerializer, keys, String.valueOf(defaultExpire)); return (Long) result; }
1.遇到的第一个问题:lua脚本格式问题,一定要注意换行和空格
2.遇到的第二个问题:一定要指定序列化方式
如图第二个和第三个参数分别对应传参序列化方式和返回结果序列化方式
3.解释一下redis lua脚本含义
1.通过redis.call(arg1, arg2)执行redis命令,arg1指的是具体的redis command,arg2指的是redis key
2.KEYS[1] 指的是需要传入的key,ARGV[1]指的是需要传入的具体的value,两者都可以定义多个
如图key需要传入一个list集合(把多个key放入集合),argv传入可变长参数(如果有多个传多个)