package com.mes.device.service.impl;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.mes.device.entity.EngineeringSequence;
|
import com.mes.device.mapper.EngineeringSequenceMapper;
|
import com.mes.device.service.EngineeringSequenceService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.LocalDate;
|
import java.time.ZoneId;
|
import java.time.format.DateTimeFormatter;
|
import java.util.Date;
|
|
/**
|
* 工程序号信息服务实现类
|
*
|
* @author mes
|
* @since 2024-11-20
|
*/
|
@Slf4j
|
@Service
|
public class EngineeringSequenceServiceImpl extends ServiceImpl<EngineeringSequenceMapper, EngineeringSequence> implements EngineeringSequenceService {
|
|
// 日期格式化器(线程不安全,使用ThreadLocal保证线程安全)
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String generateAndSaveEngineeringId(Date date) {
|
// 乐观重试,防止并发写入造成重复键
|
int retry = 0;
|
final int maxRetry = 5;
|
while (true) {
|
try {
|
// 1. 查询当天最大序号,并加行锁避免并发重复
|
Integer maxSequence = baseMapper.selectMaxSequenceByDateForUpdate(date);
|
if (maxSequence == null) {
|
maxSequence = 0;
|
}
|
|
// 2. 序号自增1
|
int newSequence = maxSequence + 1;
|
|
// 3. 生成工程号:P + yyMMdd + 两位序号
|
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
String dateStr = localDate.format(DATE_FORMATTER);
|
String engineeringId = "P" + dateStr + String.format("%02d", newSequence);
|
|
// 4. 保存到数据库
|
EngineeringSequence engineeringSequence = new EngineeringSequence();
|
engineeringSequence.setEngineeringId(engineeringId);
|
engineeringSequence.setDate(date);
|
engineeringSequence.setSequence(newSequence);
|
engineeringSequence.setCreatedTime(new Date());
|
engineeringSequence.setUpdatedTime(new Date());
|
engineeringSequence.setCreatedBy("system");
|
engineeringSequence.setUpdatedBy("system");
|
|
save(engineeringSequence);
|
|
log.info("生成工程号成功: engineeringId={}, date={}, sequence={}", engineeringId, date, newSequence);
|
return engineeringId;
|
|
} catch (DuplicateKeyException dup) {
|
// 并发导致的唯一键冲突,重试
|
if (++retry > maxRetry) {
|
log.error("生成工程号重试超过上限, date={}", date, dup);
|
throw new RuntimeException("生成工程号失败", dup);
|
}
|
log.warn("工程号生成发生并发冲突,准备重试,第{}次,date={}", retry, date);
|
} catch (Exception e) {
|
log.error("生成工程号失败, date={}", date, e);
|
throw new RuntimeException("生成工程号失败", e);
|
}
|
}
|
}
|
}
|