Springboot中使用LUA脚本进行Redis操作
Springboot中使用LUA脚本进行Redis操作
·
1、引入依赖和配置
引入spring-boot-starter-data-redis依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件中配置redis连接信息
spring:
redis: # redis配置
host: 127.0.0.1
port: 6379
database: 0
lettuce:
pool:
# 连接池最大连接数 默认8 ,负数表示没有限制
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1
max-wait: -1
# 连接池中的最大空闲连接 默认8
max-idle: 8
# 连接池中的最小空闲连接 默认0
min-idle: 0
配置RedisTemplate
@Configuration
public class LettuceConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用fastjson作为序列化器,需要引入相关依赖
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 一般redis的key为String, value为Object
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(fastJsonRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(fastJsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
2、使用LUA脚本解决库存扣减的原子性问题
这里的是productCode对应的库存提前预加载到了Redis中,扣减时从Redis中扣减,需要想获取当前库存,判断库存是否满足扣减条件,满足时进行库存扣减。但是这个过程涉及到查询而后更新,不是原子的,在大并发下场景下会出现数据不一致问题,使用LUA脚本来解决。
public DataResponse<Object> panicBuying(String productCode, Integer quantity) {
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
//设置返回值类型
redisScript.setResultType(Long.class);
//设置lua脚本文件路径
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/panicBuying.lua")));
List<String> keys = new ArrayList<>();
keys.add(productCode);
Long resCode = (Long)redisTemplate.opsForHash().getOperations().execute(redisScript, keys, quantity);
Assert.isTrue(resCode!=null,"execute lua script error");
String msg="success to decrement stock";
if(resCode==1) {
msg = "stock is not enough";
} else if(resCode==2) {
msg = "product not exist";
}
return new DataResponse<>(msg);
}
LUA脚本内容如下:
local productCode=KEYS[1]
local buyQty = tonumber(ARGV[1])
local productExist = redis.call('exists',productCode)
redis.log(redis.LOG_DEBUG, productExist)
if productExist == 1 then
local curStock = tonumber(redis.call('get',productCode))
redis.log(redis.LOG_DEBUG, curStock)
if curStock > 0 and curStock-buyQty >= 0 then
redis.call('decrby',productCode,buyQty)
return 0;
else
return 1;
end
else
return 2;
end
更多推荐
已为社区贡献2条内容
所有评论(0)