package com.fdkankan.contro.service.impl; 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.CommonStatus; import com.fdkankan.common.constant.ErrorCode; import com.fdkankan.common.exception.BusinessException; import com.fdkankan.common.util.RandomUtil; import com.fdkankan.contro.entity.Scene3dNum; import com.fdkankan.contro.enums.CameraTypeEnum; import com.fdkankan.contro.mapper.IScene3dNumMapper; import com.fdkankan.contro.service.IScene3dNumService; 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 lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; /** *

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

* * @author dengsixing * @since 2021-12-23 */ @Slf4j @Service public class Scene3dNumServiceImpl extends ServiceImpl implements IScene3dNumService { @Autowired private RedisUtil redisUtil; @Autowired private RedisLockUtil redisLockUtil; @Value("${scene.num.cachePageSize:500}") private int cachePageSize; @Value("${scene.num.threshold:10000}") 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); } // 分布式加锁 boolean lock = redisLockUtil.lock(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS, RedisKey.EXPIRE_TIME_10_MINUTE); if (lock) { try { log.info("开始加载场景码缓存"); List nums = this.findSceneNum(cachePageSize); if(CollectionUtils.isEmpty(nums)){ batchCreateSceneNum(true); nums = this.findSceneNum(cachePageSize); }else{ CompletableFuture.runAsync(() -> batchCreateSceneNum(false)); } redisUtil.lRightPushAll(RedisKey.FDKANKAN_SCENE_NUMS, nums); this.update(new LambdaQueryWrapper().in(Scene3dNum::getCode, nums)); // this.updateUsedStatus(nums); log.info("场景码加载缓存完成"); } catch (Exception e) { log.error("场景码加载缓存失败", e); } finally { redisLockUtil.unlockLua(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS); } }else{ // 等待2秒加载缓存 try { Thread.sleep(2000); } 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(boolean force) { if (!force) { 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.parallelStream().map(num -> { Scene3dNum scene3dNum = new Scene3dNum(); scene3dNum.setCode(num); return scene3dNum; }).collect(Collectors.toList()); try{ this.saveBatch(scene3dNumList); }catch (Exception e){ log.error("场景码插入异常!"); e.printStackTrace(); } } } private Set turnCreateSceneNum(int cnt){ Set numSet = new HashSet<>(); for(int i = 0; i < cnt; i++){ numSet.add(numPrefix + RandomUtil.generateShortUuid()); } return numSet; } @Override public List findSceneNum(int pageSize) { return baseMapper.findSceneNum(pageSize); } @Override public void updateUsedStatus(List nums) { baseMapper.updateUsedStatus(nums); } }