令牌验证

在确认订单操作和提交订单操作中,要分别生成一个 token 令牌、 校验 token 令牌,保证幂等性。

生成并保存令牌

Token = 前缀 + 业务对象ID + UUID

// UUID作为令牌
String token = UUID.randomUUID().toString().replace("-", "");
// 在业务对象中保存 token
orderConfirmVo.setOrderToken(token);
// 使用 redis 保存 token,并设置过期时间:30分钟
stringRedisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), token, 30, TimeUnit.MINUTES);

验证令牌

对令牌的对比和删除必须保证原子性

  1. 从 redis 和业务对象中分别获取 token
String redisOrderToken = stringRedisTemplate.opsForValue().get(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId());
String orderToken = orderSubmitVo.getOrderToken();
  1. Lua 脚本保证原子性
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
  1. 执行脚本,进行对比
Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()), orderToken);

返回 0 代表失败, 1 代表成功。