在确认订单操作和提交订单操作中,要分别生成一个 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);对令牌的对比和删除必须保证原子性。
从 redis 和业务对象中分别获取 token String redisOrderToken = stringRedisTemplate.opsForValue().get(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()); String orderToken = orderSubmitVo.getOrderToken(); Lua 脚本保证原子性 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; 执行脚本,进行对比 Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()), orderToken);返回 0 代表失败, 1 代表成功。
