高并发中,redis中利用Lua减库存,解决超卖问题

2,621 阅读1分钟
public class RedisLua {    
public static final String STOCK_LUA;    
static {       
 /**         * 扣减库存Lua脚本(一次扣减一个库存)         
* KEYS[1]:商品数量key         
* KEYS[2]:订单key         
* ARGV[1]:订单信息         
* -1:库存不足         
* -2:重复下单         
* 大于等于0:剩余库存(扣减之后剩余的库存)         
*/       
StringBuilder sb = new StringBuilder();        
sb.append("local goodsKey = KEYS[1];");        
sb.append("local orderKey = KEYS[2];");        
sb.append("local orderValue = ARGV[1];");        
sb.append("local goodsNum = redis.call('get', goodsKey);");        
sb.append("local order = redis.call('get', orderKey);");        
sb.append("if goodsNum < '1' then");        
sb.append("   return -1;");        
sb.append("end;");        
sb.append("if order == false then");        
sb.append("   redis.call('set', orderKey , orderValue);");        
sb.append("      return redis.call('decrBy', goodsKey, '1');");        
sb.append("else");        
sb.append("   return -2;");        
sb.append("end;");       
 STOCK_LUA = sb.toString();     

 /**         
* 扣减库存Lua脚本(一次扣减多个库存)         
* KEYS[1]:商品数量key         
* KEYS[2]:订单key         
* ARGV[1]:扣减数量         
* ARGV[2]:订单信息        
 * -1:库存不足         
* -2:重复下单         
* 大于等于0:剩余库存(扣减之后剩余的库存)         
*/      
 /*StringBuilder sb = new StringBuilder();        
sb.append("local goodsKey = KEYS[1];");        
sb.append("local orderKey = KEYS[2];");        
sb.append("local decrNum = ARGV[1];");        
sb.append("local orderValue = ARGV[2];");        
sb.append("local goodsNum = redis.call('get', goodsKey);");        
sb.append("local order = redis.call('get', orderKey);");        
sb.append("if goodsNum < decrNum then");        
sb.append("   return -1;");       
 sb.append("end;");        
sb.append("if order == false then");        
sb.append("   redis.call('set', orderKey , orderValue);");       
 sb.append("      return redis.call('decrBy', goodsKey, decrNum);");       
 sb.append("else");       
 sb.append("   return -2;");       
 sb.append("end;");       
 STOCK_LUA = sb.toString();*/    }}利用

使用redisTemplate执行lua脚本

List<String> keys = Arrays.asList("goodsKey:85265602","OrderKey:457811515"); 
String [] arg = {"1232555"};
DefaultRedisScript<Long> stringDefaultRedisScript = new DefaultRedisScript<>(); 
stringDefaultRedisScript.setResultType(Long.class); 
stringDefaultRedisScript.setScriptText(STOCK_LUA);  // STOCK_LUA对应脚本文本
Long res = redisTemplate.execute(stringDefaultRedisScript,keys,arg);