`
zy116494718
  • 浏览: 470741 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

redis分布式锁实现

 
阅读更多

        做项目时遇到一个功能,需要3步,1)通过solr取一个已审核数,然后和可通过数进行比较  2)更新数据库审核状态 3)更新solr已审核数  ,这时遇到一个问题,就是当用户进行批量审核的时候,这时比如有10个品被审核,那这10个请求可能会被同时打到10个机器上,然后同时执行上段代码(1,2,3步),这时就有可能出现高并发的问题,比如现在已经审核了9个商品,然后最多审核10个,两个请求同时进来,第一个请求读取到的是9,然后开始执行2和3步,结果还没执行完3,第二个请求就进来了,这时他读到的也是9(由于还没重刷solr),所以就会导致多审核了一个商品。

       由于是多台机器并发问题,所以不能只用Synchroinzed这种,故这里采用分布式锁方式。

      

        String lockKey = null;
        if(RoutineType.SEC_KILL.isEqual(activity.getRoutineType())){ //秒杀频道
            CheckGroup group = routineCheckGroupService.getCheckGroupByErpPin(activity.getChannelID(),erpPin);
            if(group!=null && pageView.getRoleType()!=1 && routineCheckGroupService.isLeafCheckGroupUser(group.getId())){   //如果是末级审核组,roleType=1为运营审核
                lockKey = this.acquireCheckLock(group.getId(), applyWare.getBatchId());
                int allCanAssign = queryAssignedBatchResourceCount(group.getId(), applyWare.getBatchId());//查询审核组在当前批次上已分配到的资源数
                int hasPassed = checkActivityService.queryHasPassedNum(Arrays.asList(group.getId()), applyWare.getBatchId());
                LogTypeEnum.ROUTINE_CHECK_RECOMMEND.warn("passApply hasPassed:{}, allCanAssign:{}", hasPassed, allCanAssign);
                if(hasPassed + 1 > allCanAssign){
                    result.setSuccess(false);
                    result.setResultCode("当前批次可审核通过"+ allCanAssign +"条,已审核通过" + hasPassed + "条,通过数量超过最大限制!");
                    return result;
                }
            }
        }

this.releaseCheckLock(lockKey);//释放分布式锁

  

 /**
     * 获得审核操作时的分布式锁
     */
    private String acquireCheckLock(final Long checkGroupId, final Long batchId) {
        String lockKey = "Check_Lock_" + checkGroupId + "_" + batchId;
        int tryTimes = 0;
        while(true) {  //如果没获得锁,会一直循环,直到超过60次
            int lockSeconds = 120;//120秒后过期, 在业务执行完成后会主动删除锁
            if (redisClient.setnx(lockKey, "1") > 0) {//锁不存在,则获取锁成功
                redisClient.expire(lockKey, lockSeconds);
                LogTypeEnum.ROUTINE_CHECK_RECOMMEND.warn("审核操作获得锁lockKey:{}, tryTimes:{}", lockKey, tryTimes);
                break;
            }
            tryTimes ++;
            try {
                if (redisClient.ttl(lockKey) < 0) {//防止上一操作加锁成功,但设置过期语句执行失败; [当 key 存在但没有设置剩余生存时间时,返回 -1]
                    redisClient.expire(lockKey, 1);//迅速过期
                }
                LogTypeEnum.ROUTINE_CHECK_RECOMMEND.warn("审核操作没有获得锁 lockKey:{}, tryTimes:{}", lockKey, tryTimes);
                Thread.sleep(2000);//休眠 2 秒
            } catch (InterruptedException e) {
            }
            if (tryTimes > 60) {
                throw new RuntimeException("审核操作等待超时!");
            }
        }
        return lockKey;
    }

   

    /**
     * 释放审核操作时获得的分布式锁
     */
    private void releaseCheckLock(final String checkLock) {
        if (checkLock != null) {
            redisClient.del(checkLock);
        }
    }

 

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics