fix(pricing): 优化优惠券打印流水号生成逻辑

-引入 AtomicLong 作为原子计数器,确保流水号的唯一性
- 修改生成流水号的方法,使用毫秒级时间戳和原子计数器组合
- 新方案解决了原方法在高并发情况下可能出现的重复流水号问题
- 优化了 FaceEntity 查询逻辑,确保 faceId 属于当前用户
This commit is contained in:
2025-08-24 15:43:14 +08:00
parent 0204b3bc23
commit ea9945b9e0

View File

@@ -23,6 +23,7 @@ import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* 优惠券打印服务实现 * 优惠券打印服务实现
@@ -44,7 +45,9 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
private RedisTemplate<String, String> redisTemplate; private RedisTemplate<String, String> redisTemplate;
private static final String PRINT_LOCK_KEY = "voucher_print_lock:%s:%s:%s"; // faceId:brokerId:scenicId private static final String PRINT_LOCK_KEY = "voucher_print_lock:%s:%s:%s"; // faceId:brokerId:scenicId
private static final String CODE_PREFIX = "VT"; // Voucher Ticket
// 原子计数器,确保流水号唯一性
private static final AtomicLong counter = new AtomicLong(0);
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@@ -56,9 +59,11 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
if (request.getBrokerId() == null) { if (request.getBrokerId() == null) {
throw new BaseException("经纪人ID不能为空"); throw new BaseException("经纪人ID不能为空");
} }
if (request.getScenicId() == null) { FaceEntity face = faceRepository.getFace(request.getFaceId());
throw new BaseException("景区ID不能为空"); if (face == null) {
throw new BaseException("请上传人脸");
} }
request.setScenicId(face.getScenicId());
Long currentUserId = Long.valueOf(BaseContextHandler.getUserId()); Long currentUserId = Long.valueOf(BaseContextHandler.getUserId());
@@ -149,13 +154,16 @@ public class VoucherPrintServiceImpl implements VoucherPrintService {
} }
/** /**
* 生成流水号 * 生成流水号(优化版本)
* 使用原子计数器确保唯一性,解决原方法在高并发下的重复问题
*/ */
private String generateCode() { private String generateCode() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); // 方案:使用毫秒级时间戳 + 原子计数器
// 格式:5位计数器 + SSS
SimpleDateFormat sdf = new SimpleDateFormat("SSS");
String timestamp = sdf.format(new Date()); String timestamp = sdf.format(new Date());
String randomSuffix = String.valueOf((int)(Math.random() * 1000)).formatted("%03d"); long count = counter.incrementAndGet() % 100000; // 5位计数,循环使用
return CODE_PREFIX + timestamp + randomSuffix; return String.format("%05d", count) + timestamp;
} }
/** /**