先说明下遇到的问题,我这边有两个请求,
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 RedisTemplateredisTemplate; //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 RedisTemplateredisTemplate; 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(),
如果对您有帮助,请点赞三连谢谢。



