订单的防重复提交(接口幂等性)-Lua脚本

274集 E:\BaiduNetdiskDownload\谷粒商城\课件和文档\高级篇\课件\02、接口幂等性.pdf

解决方法:

token 令牌机制

token是存在redis里的
1查询得到token
2对比redis里的token和前端页面传过来的token
3对比成功删除token(这样后面来的请求就拿不到token)
对比成功删除tokrn后执行业务操作

123操作必须是原子性 可用Lua脚本保证原子性

锁机制

1、数据库悲观锁
select * from xxxx where id = 1 for update;
悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,需要根据实际情况选用。 另外要注意的是,id 字段一定是主键或者唯一索引,不然可能造成锁表的结果,处理起来会 非常麻烦。

2、数据库乐观锁 这种方法适合在更新的场景中,
update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
根据 version 版本,也就是在操作库存前先获取当前商品的 version 版本号,然后操作的时候 带上此 version 号。我们梳理下,我们第一次操作库存时,得到 version 为 1,调用库存服务 version 变成了 2;但返回给订单服务出现了问题,订单服务又一次发起调用库存服务,当订 单服务传如的 version 还是 1,再执行上面的 sql 语句时,就不会执行;因为 version 已经变 为 2 了,where 条件就不成立。这样就保证了不管调用几次,只会真正的处理一次。 乐观锁主要使用于处理读多写少的问题

276集

 /**
     *   点击提交订单执行后的方法   校验请求的令牌(防止重复提交) 锁库存
     */
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo) {
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
        MemberEntity memberEntity = LoginUserInterceptor.threadLocal.get();
        String webOrderToken  = orderSubmitVo.getOrderToken();
        //1.校验令牌
        // 【对比前端传过来的令牌与redis里存的令牌  对比成功后删除令牌】这两个操作必须是原子的
        //否则  如果连着点击两次提交订单 第一次令牌对比完了 还没删除redis 第二次点击的请求来了又对比成功了
        //对比成功了就继续执行下面的代码了  所以必须保证一个请求的对比和删除redis里的令牌数据 这两个操作是原子的
        //这样第一次点击的请求 对比完了  删掉redis里的防重复令牌数据  第二次点击的请求再来对比就对比失败 不相等了
        //这样就实现了防重复提交的功能
           保证两个操作的原子性   可以用Lua脚本  讲分布式锁的时候也用到了Lua脚本
        //Lua脚本返回0或1   0就是令牌对比失败  1就是对比成功删除redis里的令牌数据成功
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long resultLua = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberEntity.getId()),
                webOrderToken);
        if(resultLua == 0L){
            //令牌验证失败
            return responseVo;
        }else{
            //令牌验证成功
            //执行创建订单 锁库存
        }


//script   这个Lua脚本就相当于下面被注释的这几句
//        String redisUserToken = stringRedisTemplate.opsForValue()
//                .get(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberEntity.getId());
//        if(redisUserToken != null && redisUserToken.equals(orderSubmitVo.getOrderToken())){
//            //验证防重令牌通过后删除当前这个令牌
//        }
     return null;
    }

你可能感兴趣的:(分布式电商,lua,redis,数据库)