前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >redis锁和等待锁随机毫秒数解决程序调用方控制执行的先后顺序,避免并发操作造成的数据不一致

redis锁和等待锁随机毫秒数解决程序调用方控制执行的先后顺序,避免并发操作造成的数据不一致

作者头像
oktokeep
发布2024-11-28 09:11:05
发布2024-11-28 09:11:05
970
举报
文章被收录于专栏:第三方工具

redis锁和等待锁随机毫秒数解决程序调用方控制执行的先后顺序,避免并发操作造成的数据不一致

现象: 向第三方服务调用接口,比如更换商品换货,需要先取消,然后再新增操作。 同时可能存在修改并发操作(同时操作换货和修改操作),在取消和新增的间隙中做了修改操作,引起脏数据等数据不一致的问题。 导致修改的数据,在新增操作后,未生效。

解决方案: 基于的前提是在程序接口的调用方来控制先后执行顺序,服务提供方本身提供的是取消,新增,修改3个独立的接口,只是业务上需要将取消和新增组合起来使用。 redis锁定5秒来处理,控制加锁优化

期望:将取消和新增作为一个“事务”来处理,只有这一个“换货”的操作完成之后,才允许做修改操作。

代码语言:javascript
复制
//伪代码
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
//修改接口{
    String redisKey = "key" + orderDTO.getOrdernumber();
    Boolean haskey = stringRedisTemplate.hasKey(redisKey);
    LocalDateTime startTime = LocalDateTime.now();
    LocalDateTime endTime = startTime.plusSeconds(5);
    
    //已被锁定,直接返回,等待 + redis锁释放和程序时间5秒双重判断,避免redis释放锁异常导致永远在等待的现象。
        while ( haskey && (startTime.isBefore(endTime) || startTime.isEqual(endTime)) ) {
            try {
                long time = (long) (Math.random() * 1000);
                Thread.sleep(time);
                //重新查询
                haskey = stringRedisTemplate.hasKey(redisKey);
                //重新刷新时间
                startTime = LocalDateTime.now();
                log.info("testlogger >> 修改订单 判断锁存在,orderNo=[{}],haskey=[{}],waitTime=[{}]",orderDTO.getOrdernumber(),haskey,time);
            } catch (InterruptedException e) {
                log.error("exceotion:",e);
            }
        }
        
    //继续修改操作 ……    
}


//换货接口(取消和新增){
    String redisKey = "key" + orderDTO.getOrdernumber();
    Boolean haskey = stringRedisTemplate.hasKey(redisKey);
    try {
        //加锁
        if(haskey) {
            //已被锁定,直接返回,无需重复加锁
            log.info("testlogger 锁已经存在,无需重复加锁,orderNo=[{}]",cancelFlowOrderDTO.getOrdernumber());
        } else {
            stringRedisTemplate.opsForValue().set(redisKey, "1", 5, TimeUnit.SECONDS);
            log.info("testlogger 锁不存在,需要加锁,orderNo=[{}]",cancelFlowOrderDTO.getOrdernumber());
        }
        
        //换货操作(取消和新增)……
        

    }catch (Exception e) {
        log.error("取消新增接口异常:",e);
        if(haskey != null && haskey) {
            stringRedisTemplate.delete(redisKey);
            log.info("testlogger 锁存在,异常释放锁,orderNo=[{}]",cancelFlowOrderDTO.getOrdernumber());
        }
    }finally {
        if(haskey != null && haskey) {
            //释放锁
            stringRedisTemplate.delete(redisKey);
            log.info("testlogger 锁存在,正常释放锁,orderNo=[{}]",cancelFlowOrderDTO.getOrdernumber());
        }
    }
}        
        
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档