소스 검색

计量编号加锁

cr 1 일 전
부모
커밋
081f8ddaa1

+ 18 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/config/RedissonConfig.java

@@ -0,0 +1,18 @@
+package org.springblade.meter.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+    @Bean
+    public RedissonClient redissonClient() {
+        Config config = new Config();
+        config.useSingleServer()
+                .setAddress("redis://127.0.0.1:6379");
+        return Redisson.create(config);
+    }
+}

+ 61 - 2
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MiddleMeterApplyController.java

@@ -16,19 +16,25 @@
  */
 package org.springblade.meter.controller;
 
+import com.alibaba.nacos.shaded.com.google.protobuf.ServiceException;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 
 import javax.validation.Valid;
 
+import org.redisson.Redisson;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.meter.dto.MiddleMeterApplyDTO;
 import org.springblade.meter.dto.WbsNodeDTO;
 import org.springblade.meter.entity.AttachmentForm;
 import org.springblade.meter.vo.*;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -39,6 +45,7 @@ import org.springblade.core.boot.ctrl.BladeController;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 中间计量申请表 控制器
@@ -53,6 +60,9 @@ import java.util.List;
 public class MiddleMeterApplyController extends BladeController {
 
     private final IMiddleMeterApplyService middleMeterApplyService;
+    private final BladeRedis bladeRedis;
+    @Autowired
+    private  RedissonClient redissonClient;
 
 
     /**
@@ -205,10 +215,59 @@ public class MiddleMeterApplyController extends BladeController {
             @ApiImplicitParam(name = "contractId", value = "合同id", required = true),
             @ApiImplicitParam(name = "contractPeriodId", value = "合同计量期id", required = true)
     })
-    public R<String> getMeterNumber(MiddleMeterApply middleMeterApply) {
-        return R.data(middleMeterApplyService.getMeterNumber(middleMeterApply));
+    public R<String> getMeterNumber(MiddleMeterApply middleMeterApply) throws ServiceException {
+        RLock lock = redissonClient.getLock("getMeterNumber:" + middleMeterApply.getContractId() + ":" + middleMeterApply.getContractPeriodId());
+        // 不指定leaseTime,Redisson会自动续期(默认30秒,可通过Config配置)
+        lock.lock();
+        try {
+            String meterNumber = middleMeterApplyService.getMeterNumber(middleMeterApply);
+            String redisKey = "getMeterNumber:" + middleMeterApply.getContractId() + ":" + middleMeterApply.getContractPeriodId() + ":" + meterNumber;
+
+            if (bladeRedis.exists(redisKey)) {
+                // 初始编号已存在,生成新编号
+                String meterNumber1 = getMeterNumber1(meterNumber, middleMeterApply.getContractId(), middleMeterApply.getContractPeriodId());
+                String newRedisKey = "getMeterNumber:" + middleMeterApply.getContractId() + ":" + middleMeterApply.getContractPeriodId() + ":" + meterNumber1;
+                bladeRedis.setEx(newRedisKey, meterNumber1, 300L);
+                return R.data(meterNumber1); // 返回新编号
+            } else {
+                bladeRedis.setEx(redisKey, meterNumber, 300L);
+                return R.data(meterNumber);
+            }
+        } finally {
+            // 确保锁释放(判断是否持有锁,避免异常场景下误释放)
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+
+    public String getMeterNumber1(String meterNumber, Long contractId, Long contractPeriodId) throws ServiceException {
+        // 校验编号格式,避免substring异常
+        int lastDashIndex = meterNumber.lastIndexOf("-");
+        if (lastDashIndex == -1) {
+            throw new ServiceException("编号格式错误,缺少分隔符 '-'");
+        }
+        String prefix = meterNumber.substring(0, lastDashIndex + 1);
+        int lastNumber = Integer.parseInt(meterNumber.substring(lastDashIndex + 1));
+
+        // 循环生成新编号,直到不存在于Redis中
+        while (true) {
+            lastNumber++;
+            String newMeterNumber = prefix + lastNumber;
+            String redisKey = "getMeterNumber:" + contractId + ":" + contractPeriodId + ":" + newMeterNumber;
+            // 如果新编号不存在,则返回
+            if (!bladeRedis.exists(redisKey)) {
+                return newMeterNumber;
+            }
+            // 防止无限循环(极端情况:连续N个编号都被占用,可加最大次数限制)
+            if (lastNumber > 1000) { // 例如最多尝试1000次
+                throw new ServiceException("生成编号失败,尝试次数过多");
+            }
+        }
     }
 
+
+
     /**
      * 获取本期计量总金额
      */