• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

SpringBoot通过RedisTemplate执行Lua脚本的方法步骤

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

参考:

https://www.ogeek.net/article/212010.htm

https://www.ogeek.net/article/179946.htm

https://www.jianshu.com/p/76bc0e963172

https://www.letianbiji.com/redis/redis-lua.html

https://www.ogeek.net/article/148833.htm

 

Redis从2.6版本开始引入对Lua脚本的支持,通过在服务器中嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务端原子的执行多个Redis命令。

其中,使用EVAL命令可以直接对输入的脚本进行求值:

1
2
redis>EVAL "return 'hello world'" 0
"hello world"

使用脚本的好处如下:

1.减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在redis服务器上完成。使用脚本,减少了网络往返时延。

2.原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。

3.复用:客户端发送的脚本会永久存储在Redis中,意味着其他客户端可以复用这一脚本而不需要使用代码完成同样的逻辑。

 

 

第一步:redis配置

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


@Configuration
@EnableCaching //引入缓存
public class RedisConfig {

/**
* RedisTemplate配置
* @param redisConnectionFactory
* @return
*/
@Primary
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper()
.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule()); // new module, NOT JSR310Module;;
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
// key序列化
redisTemplate.setKeySerializer(stringSerializer);
// value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}

}

第二步:写lua脚本

 

 redis_lock4.lua的内容:

if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then
return redis.call('expire',KEYS[1],ARGV[2])
else
return -1000
end

解释 :setnx命令, 设置 KEYS[1]的值为ARGV[1], 并设置KEYS[1]的过期时间为ARGV[2]。
如设置prize_stock的值为100,并设置prize_stock的过期时间为200秒。

第三步:代码
Long result = null;
try {
//调用lua脚本并执行
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);//返回类型是Long
//lua文件存放在resources目录下的redis文件夹内
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_lock4.lua")));
result = redisTemplate.execute(redisScript, Arrays.asList("prize_stock"), 100, 300);
System.out.println("lock==" + result);
} catch (Exception e) {
e.printStackTrace();
}

 

 

 解释: 

Arrays.asList("prize_stock") 为KEYS, lua脚本对应 KEYS[1]
100, 300为参数,lua脚本对应ARGV[1] 和 ARGV[2]。


---------------------------------------------------------
仅记录,没用:
加锁:
if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then
return redis.call('expire',KEYS[1],ARGV[2])
else
return -1000
end

解锁:

if redis.call("exists",KEYS[1]) == 0 then
return 100
end

if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 200
end
扣库存:
if (redis.call('exists', KEYS[1]) == 1) then
local stock = tonumber(redis.call('get', KEYS[1]))
local num = tonumber(ARGV[1])
if (stock >= num) then
return redis.call('incrby', KEYS[1], 0 - num)
end
end
return -100



 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
lua脚本相关命令发布时间:2022-07-22
下一篇:
lua——赢三张牌型处理相关算法(中)——牌型判定发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap