先说明下遇到的问题,我这边有两个请求,
1. key = a; num= 10
通过Redis 检查 某key的value的值,检查是否大于num,如果小于,则不扣除。如果大于则扣除 ,并返回扣除后的数值
2.key1 = a;key2 = b; num = 10
.通过Redis 对两个key的value进行检查,检查两个key的value和是否大于num,如果小于,则不扣除。如果大于,先扣除key为a的value,如果a不够扣,再扣除key为b的value。并返回json字符串,分别写入a和b所扣除的数值
这里通过Redis进行处理
环境:
JDK1.8
SprintBoot 2.2.6.RELEASE
spring-data-redis-2.2.6.RELEASE
1.第一个需求,这个是常见的预扣校验的需求。
@Resource
private RedisTemplate redisTemplate;
//LUA脚本,也可以采用外置文件的方式读取
private static final String SUBTRACT_LUA = new StringBuilder()
.append("if (redis.call('exists', KEYS[1]) == 1) then")
.append(" local temp = tonumber(redis.call('get', KEYS[1]));")
.append(" local num = tonumber(ARGV[1]);")
.append(" if (temp >= num) then")
.append(" return redis.call('incrby', KEYS[1], 0 - num);")
.append(" end;")
.append(" return -2;")
.append("end;")
.append("return -1;").toString();
public Long subtract(String key, Long number, Long initNumber) {
long result = subtract(key, number);
// 初始化
if (result == -1) {
redisTemplate.opsForValue().setIfAbsent(key, initNumber);
result = subtract(key, moneyNum);
}
//余额不足,返回null
if (result == -2) {
return null;
}
return result;
}
//实际扣除方法,成功返回扣除后数值,失败返回 -2 或 -1
private Long subtract(String key, Long num) {
// 脚本里的KEYS参数
List keys = new ArrayList<>();
keys.add(key);
DefaultRedisScript longDefaultRedisScript = new DefaultRedisScript<>();
longDefaultRedisScript.setResultType(Long.class);
longDefaultRedisScript.setScriptSource(new StaticScriptSource(SUBTRACT_LUA));
Long result = redisTemplate.execute(longDefaultRedisScript, keys, num);
return result;
}
2.第二个需求,需要返回拼接的字符串。
@Resource
private RedisTemplate redisTemplate;
public static final String SUBTRACTS_LUA = new StringBuilder()
.append("if (redis.call('exists', KEYS[1]) == 1 and redis.call('exists', KEYS[2]) == 1) then")
.append(" local temp1 = tonumber(redis.call('get', KEYS[1]));")
.append(" local temp2 = tonumber(redis.call('get', KEYS[2]));")
.append(" local num = tonumber(ARGV[1]);")
.append(" local temp = temp1 + temp2;")
.append(" if (temp >= num) then")
.append(" if (temp1 >= num) then")
.append(" redis.call('incrby', KEYS[1], 0 - num);")
.append(" return string.format('{\"'..KEYS[1]..'\":%d}', num);")
.append(" else")
.append(" redis.call('set', KEYS[1], 0);")
.append(" local num = (num - temp1);")
.append(" redis.call('incrby', KEYS[2], 0 - num);")
.append(" return string.format('{\"'..KEYS[1]..'\":%d, \"'..KEYS[2]..'\":%d}', temp1, num);")
.append(" end;")
.append(" end;")
.append(" return '-2';")
.append("end;")
.append("return '-1';").toString();
public Map subtracts(String key1, String key2, Long number, Long initNumber1, Long initNumber2) {
String result = subtracts(key1, key2, number);
// 初始化
if ("-1".equals(result)) {
redisTemplate.opsForValue().setIfAbsent(key1, initNumber1);
redisTemplate.opsForValue().setIfAbsent(key2, initNumber2);
result = subtracts(key1, key2, number);
}
//数值不足,返回null
if ("-2".equals(result)) {
return null;
}
JSONObject jsonObject = JSONUtil.parseObj(result);
Map r = new HashMap<>();
r.put(key1, jsonObject.getLong(key1));
r.put(key2, jsonObject.getLong(key2));
return r;
}
private String subtracts(String key1, String key2, Long num) {
DefaultRedisScript defaultRedisScript = new DefaultRedisScript<>();
defaultRedisScript.setResultType(String.class);
defaultRedisScript.setScriptSource(new StaticScriptSource(SUBTRACTS_LUA));
return redisTemplate.execute(defaultRedisScript, redisTemplate.getValueSerializer(), redisTemplate.getStringSerializer(),
Lists.newArrayList(key1, key2), num);
}
主要遇到坑的地方是Redis入参和返回序列化的问题。
redisTemplate.execute(defaultRedisScript, redisTemplate.getValueSerializer(), redisTemplate.getStringSerializer(),
如果对您有帮助,请点赞三连谢谢。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)