瀏覽代碼

主订单加锁

wanghao 2 周之前
父節點
當前提交
eb02386a68

+ 2 - 2
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/UnifyOrderManager.java

@@ -283,8 +283,8 @@ public class UnifyOrderManager {
                 .getCompanyCode(), quoteVo.getOrder()
                 .getApiType(), sysQuoteConfigService, sysQuoteRedisService, platformClient, baseController);
 
-        // 生成主订单及子订单  返回子订单id
-        String ordersNo = insOrdersService.generateOrders(quoteVo, companyName, systemCode, quoteVo.getOrder().getProductId());
+        // 生成主订单及子订单  返回子订单id(带分布式锁,同车同险种并发时串行)
+        String ordersNo = insOrdersService.generateOrdersWithLock(quoteVo, companyName, systemCode, quoteVo.getOrder().getProductId());
 
         // 添加车辆没有的参数: 车辆明细、
         QuoteInfoParameterFilling.setParameterSettings(quoteVo, esmInsCompanyHttpResult.getData().getCompanyCode());

+ 11 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/InsOrdersService.java

@@ -63,6 +63,17 @@ public interface InsOrdersService extends IService<InsOrders> {
      */
     String generateOrders(QuoteVo quoteVo, String companyName, String systemCode,String productId);
 
+    /**
+     * 生成订单(带分布式锁):同车+同险种并发时串行,保证只有一个主订单,其余为子订单
+     *
+     * @param quoteVo     报价信息
+     * @param companyName 保险公司名称
+     * @param systemCode 租户代码
+     * @param productId  产品ID
+     * @return 子订单号
+     */
+    String generateOrdersWithLock(QuoteVo quoteVo, String companyName, String systemCode, String productId);
+
 
     /**
      * 获取主订单信息 用于判断是否存在主订单

+ 43 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsOrdersServiceImpl.java

@@ -62,6 +62,8 @@ import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
 import org.apache.http.util.TextUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -81,6 +83,7 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @RequiredArgsConstructor
@@ -136,6 +139,8 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
 
     private final OrderStateListener orderStateListener;
 
+    private final RedissonClient redissonClient;
+
     @Autowired
     private InsOrdersQrcodeMapper insOrdersQrcodeMapper;
 
@@ -1759,6 +1764,44 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
 
     }
 
+    /**
+     * 生成订单(带分布式锁):同车+同险种并发时串行,保证只有一个主订单,其余为子订单
+     * 锁粒度:车牌+车架+险种(不含保司,因为同车同险种只允许一个主订单)
+     * 锁释放在事务提交后(外层方法非事务,内层 generateOrders 事务返回时已提交)
+     *
+     * @param quoteVo     报价参数
+     * @param companyName 保司名称
+     * @param systemCode  系统编码
+     * @param productId   产品ID
+     * @return 子订单号
+     */
+    @Override
+    public String generateOrdersWithLock(QuoteVo quoteVo, String companyName, String systemCode, String productId) {
+        String licenseNo = quoteVo.getCarInfoVo().getLicenseNo();
+        String vinNo = quoteVo.getCarInfoVo().getVinNo();
+        // 锁 key:车+险种(同车同险种串行)
+        String lockKey = "order:generate:" + licenseNo + ":" + vinNo + ":" + productId;
+        RLock lock = redissonClient.getLock(lockKey);
+
+        try {
+            // 等锁 3 秒,持锁 30 秒(覆盖事务提交)
+            boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);
+            if (!locked) {
+                log.warn("生成订单获取锁失败,lockKey=[{}]", lockKey);
+                throw new SystemException("订单生成中,请稍后重试");
+            }
+            // 调用事务方法,return 后事务已提交,再释放锁
+            return this.generateOrders(quoteVo, companyName, systemCode, productId);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new SystemException("生成订单被中断");
+        } finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+
     /**
      * 生成一个主订单和多个子订单
      *