Эх сурвалжийг харах

计量编号获取时加锁

cr 1 өдөр өмнө
parent
commit
3523b6a202

+ 133 - 34
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MiddleMeterApplyServiceImpl.java

@@ -28,6 +28,7 @@ import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.manager.entity.ContractInfo;
@@ -83,6 +84,7 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
 
     private final IAttachmentFormServiceTask attachmentFormServiceTask;
 
+    private final BladeRedis bladeRedis;
 
 
     /**
@@ -699,53 +701,150 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
      */
     @Override
     public String getMeterNumber(MiddleMeterApply apply) {
-        //如果计量期id为-1则代表不用查询
-        if (apply.getContractPeriodId() == -1){
+        if (apply.getContractPeriodId() == -1) {
             return "";
         }
+
+        String lockKey = "meter_number:" + apply.getContractId() + ":" + apply.getContractPeriodId();
+        String requestId = UUID.randomUUID().toString();
+
+        try {
+            // 尝试获取分布式锁
+            boolean locked = false;
+            int lockRetry = 0;
+            int maxLockRetry = 3;
+
+            while (!locked && lockRetry < maxLockRetry) {
+                // 先检查是否已存在锁
+                if (!bladeRedis.exists(lockKey)) {
+                    // 不存在时尝试设置锁
+                    bladeRedis.setEx(lockKey, requestId,10L);
+                    // 再次检查确认自己是锁的持有者
+                    String currentOwner = bladeRedis.get(lockKey);
+                    if (requestId.equals(currentOwner)) {
+                        locked = true;
+                    }
+                }
+                if (!locked) {
+                    lockRetry++;
+                    try {
+                        Thread.sleep(100 * lockRetry);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                        break;
+                    }
+                }
+            }
+            if (!locked) {
+                return "";
+            }
+            // 获取锁成功后的业务逻辑
+            int maxRetries = 5;
+            int retryCount = 0;
+            while (retryCount < maxRetries) {
+                try {
+                    String number = generateMeterNumber(apply);
+                    if (!isNumberExists(number)) {
+                        return number;
+                    }
+                    retryCount++;
+                    try {
+                        Thread.sleep(100 * retryCount);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                        break;
+                    }
+                } catch (Exception e) {
+                    retryCount++;
+                }
+            }
+            return "";
+
+        } finally {
+            // 安全释放锁
+            try {
+                String currentValue = bladeRedis.get(lockKey);
+                if (requestId.equals(currentValue)) {
+                    bladeRedis.del(lockKey);
+                }
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    /**
+     * 生成计量单编号
+     */
+    private String generateMeterNumber(MiddleMeterApply apply) {
         StringBuilder str = new StringBuilder();
-        //获取合同信息
+
+        // 获取合同信息
         ContractInfo info = baseMapper.getContractInfo(apply.getContractId());
         String contractNumber = info.getContractNumber();
-        if (StringUtils.isBlank(contractNumber)){
-            throw new ServiceException("未获取到当前合同段编号信息");
+        if (StringUtils.isBlank(contractNumber)) {
+            return "";
         }
-        str.append(contractNumber+"-");
-        //获取计量期信息
+        str.append(contractNumber).append("-");
+
+        // 获取计量期信息
         ContractMeterPeriod contractMeterPeriod = contractMeterPeriodService.getById(apply.getContractPeriodId());
-        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())){
-            throw new ServiceException("未获取到计量期期号信息");
+        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())) {
+            return "";
         }
-        str.append(contractMeterPeriod.getPeriodNumber()+"-");
-        //获取流水号:当前合同段存在的当前计量期的申请单总数+1
-        List<MiddleMeterApply> allAPPly = baseMapper.getAllAPPly(apply.getContractId(), apply.getContractPeriodId());
-        if (allAPPly.size() == 0){
-            str.append(1);
-        }else {
-            List<Integer> list = allAPPly.stream().filter(l -> l.getApproveStatus() != null).map(l -> l.getApproveStatus()).sorted().collect(Collectors.toList());
-            if (list.size() == 0 || list.get(0) != 1){
-                str.append(1);
-            }else {
-                for (int i = 0; i < list.size() - 1; i++) {
-                    Integer num = list.get(i);
-                    if (num .equals(list.get(i+1)) ){
-                        throw new ServiceException("计量期期号出现相同,请联系管理员");
-                    }
-                    Integer j = ++num;
-                    String j2 = j.toString();
-                    String j3 = list.get(i + 1).toString();
-                    if (!j2.equals(j3)){
-                        str.append(num);
-                        return str.toString();
-                    }
-                }
-                str.append(list.size()+1);
-            }
+        str.append(contractMeterPeriod.getPeriodNumber()).append("-");
 
+        // 获取流水号
+        Integer nextSerial = getNextSerialNumber(apply);
+        if (nextSerial == null) {
+            log.error("获取流水号失败");
+            return "";
         }
+        str.append(nextSerial);
         return str.toString();
     }
 
+    /**
+     * 获取下一个流水号
+     */
+    private Integer getNextSerialNumber(MiddleMeterApply apply) {
+        List<MiddleMeterApply> allApply = baseMapper.getAllAPPly(apply.getContractId(), apply.getContractPeriodId());
+        if (allApply.isEmpty()) {
+            return 1;
+        }
+        // 提取已使用的流水号
+        List<Integer> usedSerials = allApply.stream()
+                .filter(l -> l.getApproveStatus() != null)
+                .map(MiddleMeterApply::getApproveStatus)
+                .sorted()
+                .collect(Collectors.toList());
+
+        if (usedSerials.isEmpty()) {
+            return 1;
+        }
+        // 查找第一个可用的流水号
+        for (int i = 0; i < usedSerials.size(); i++) {
+            if (usedSerials.get(i) != i + 1) {
+                return i + 1;
+            }
+        }
+        // 如果所有序号都连续,返回下一个
+        return usedSerials.size() + 1;
+    }
+
+    /**
+     * 检查编号是否已存在
+     */
+    private boolean isNumberExists(String number) {
+        if (StringUtils.isBlank(number)) {
+            return true; // 空编号视为已存在,需要重新生成
+        }
+        LambdaQueryWrapper<MiddleMeterApply> query = new LambdaQueryWrapper<>();
+        query.eq(MiddleMeterApply::getMeterNumber, number);
+        return count(query) > 0;
+    }
+
+
+
     /**
      * 获取本期计量总金额
      */