Spring Redis Lua 秒杀脚本

152 阅读1分钟

场景:一个商品对应库存数量为 10,一个用户id,只能购买一次

脚本逻辑:

  1. 先检查当前用户ID,是否已经存在,如果存在,直接返回 -1
  2. 如果不存在,则查询库存数量,判断库存数量是否大于0,如果大于0,才能进行减库存
  3. 扣减成功,则将用户ID,写入缓存,同时返回 1
  4. 如果库存数量已经为0了,则直接返回 0
@Test
void decrementStock4() {
  String threadName0 = getThreadName0(); // 这里可以换成购买人的id
  String stockKey = "stock";
  // 定义 Lua 脚本
  String script = "local exist = redis.call('EXISTS', KEYS[2])\n"
          + "if exist == 1 then\n"
          + "    return -1\n"
          + "end\n"
          + "local currentStock = tonumber(redis.call('GET', KEYS[1]))\n"
          + "local decrement = tonumber(KEYS[3])\n"
          + "if currentStock > 0 then\n"
          + "    redis.call('DECRBY', KEYS[1], decrement)\n"
          + "    redis.call('SET', KEYS[2], 'true')\n"
          + "    return 1\n"
          + "else\n"
          + "    return 0\n"
          + "end";

  // 执行 Lua 脚本
  RScript rScript = redissonClient.getScript();
  Long result = rScript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.INTEGER,
          Arrays.asList(stockKey, threadName0, "1"));

  // 判断执行结果
  if (result == 1) {
    System.out.println("OK::" + threadName0 + " 库存扣减成功");
  } else if (result == 0) {
    System.out.println("ERR::" + threadName0 + "库存不足,无法扣减");
  } else {
    System.out.println("ERR::" + threadName0 + "已经扣过库存,无需重复扣减");
  }
}