|
|
@@ -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();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 生成一个主订单和多个子订单
|
|
|
*
|