package com.fdkankan.scene.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fdkankan.common.constant.CameraTypeEnum; import com.fdkankan.common.constant.CommonStatus; import com.fdkankan.common.constant.ErrorCode; import com.fdkankan.common.constant.TbStatus; import com.fdkankan.common.exception.BusinessException; import com.fdkankan.common.util.RandomUtil; import com.fdkankan.redis.constant.RedisKey; import com.fdkankan.redis.constant.RedisLockKey; import com.fdkankan.redis.util.RedisLockUtil; import com.fdkankan.redis.util.RedisUtil; import com.fdkankan.scene.entity.Scene3dNum; import com.fdkankan.scene.mapper.IScene3dNumMapper; import com.fdkankan.scene.service.IScene3dNumService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; /** *

* 八目场景编码表 服务实现类 *

* * @author dengsixing * @since 2021-12-23 */ @Slf4j @Service @RefreshScope public class Scene3dNumServiceImpl extends ServiceImpl implements IScene3dNumService { private @Autowired RedisUtil redisUtil; @Autowired RedisLockUtil redisLockUtil; @Value("${scene.num.threshold:1000}") private int threshold; @Value("${scene.num.prefix:V4-}") private String numPrefix; @Value("${scene.num.batchSize:100}") private int batchSize; @Override public String generateSceneNum(Integer cameraType){ // 从缓存中获取 String sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS); if(Objects.nonNull(sceneNum)){ return addPrefix(sceneNum,cameraType); } // 分布式加锁 Long loading = redisUtil.incr(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS, 1); if (loading.compareTo(1L) == 0) { try { log.info("开始从数据库加载场景码"); List nums = this.findSceneNum(); this.updateUsedStatus(nums); redisUtil.lRightPushAll(RedisKey.FDKANKAN_SCENE_NUMS, nums); log.info("场景码加载完成"); } catch (Exception e) { log.error("场景码加载失败", e); } finally { redisUtil.decr(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS, 1); } }else{ // 等待1秒加载缓存 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS); if(StrUtil.isEmpty(sceneNum)){ log.error("场景码加载失败"); throw new BusinessException(ErrorCode.FAILURE_CODE_5053); } return addPrefix(sceneNum,cameraType); } private static String addPrefix( String num,Integer cameraType){ if(cameraType == null){ return num; } return CameraTypeEnum.getSceneNumPrefixByType(cameraType) + num; } @Override public void batchCreateSceneNum() { String lockKey = String.format(RedisLockKey.LOCK_BATCH_CREATE_NUM); boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_10_MINUTE); if(!lock){ return; } try { long count = this.count( new LambdaQueryWrapper().eq(Scene3dNum::getUsed, CommonStatus.NO.code())); if(count > threshold){ return; } int batchCnt = threshold / batchSize + (threshold % batchSize > 0 ? 1 : 0); for (int i = 0; i < batchCnt; i++){ Set numSet = this.turnCreateSceneNum(batchSize); List scene3dNumList = numSet.stream().map(num -> { Scene3dNum scene3dNum = new Scene3dNum(); scene3dNum.setNum(num); return scene3dNum; }).collect(Collectors.toList()); this.saveBatch(scene3dNumList); } }finally { redisLockUtil.unlockLua(lockKey); } } private Set turnCreateSceneNum(int cnt){ String num; Set numSet = new HashSet<>(); for(int i = 0; i < cnt; i++){ num = numPrefix + RandomUtil.generateShortUuid(); numSet.add(num); } List existList = this.list( new LambdaQueryWrapper() .in(Scene3dNum::getNum, numSet)); Set existNumSet = null; if(CollUtil.isNotEmpty(existList)){ existNumSet = existList.stream().map(Scene3dNum::getNum).collect(Collectors.toSet()); } if(CollUtil.isNotEmpty(existNumSet)){ numSet.removeAll(existNumSet); } if(numSet.size() < cnt){ numSet.addAll(this.turnCreateSceneNum(cnt - numSet.size())); } return numSet; } @Override public List findSceneNum() { return baseMapper.findSceneNum(); } @Override public Scene3dNum findByNum(String sceneCode) { List list = this.list(new LambdaQueryWrapper() .eq(Scene3dNum::getTbStatus, TbStatus.VALID.code()) .eq(Scene3dNum::getNum, sceneCode)); if(CollUtil.isEmpty(list)){ return null; } return list.get(0); } @Override public void updateUsedStatus(List nums) { baseMapper.updateUsedStatus(nums); } }