业务需要生成一个有序的编号
代码:
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, String> saveEntity(ProjectApprovalDTO dto) {
ProjectApproval entity = convert.toEntity(dto);
// 判断行政区划和行政区域是否全部为中文
if (!Validator.isChinese(dto.getDirection()) || !Validator.isChinese(dto.getRegion())) {
throw new GlobalBadRequestException("");
}
StringBuilder sb = new StringBuilder();
// 取行政区划 行政区域 拼音首字母
sb.append(StrUtil.swapCase(PinyinUtil.getFirstLetter(dto.getDirection(), StrUtil.EMPTY)))
.append(StrUtil.swapCase(PinyinUtil.getFirstLetter(dto.getRegion(), StrUtil.EMPTY))).append(StringPool.DASH)
.append(DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN)).append(StringPool.DASH);
RLock lock = redisson.getLock(LOCK_KEY);
try {
while (true) {
if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
ProjectApproval project = projectApprovalMapper.findLastedCode(sb.toString());
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumIntegerDigits(4);
formatter.setGroupingUsed(false);
long num = 1;
if (!ObjectUtil.isEmpty(project)) {
String[] split = project.getCode().split(StringPool.DASH);
String s = split[split.length - 1];
num = Integer.parseInt(s) + 1;
}
sb.append(formatter.format(num));
entity.setCode(sb.toString());
save(entity);
if (!StrUtil.isEmpty(dto.getNicheId())) {
nicheService.updateById(Niche.Builder.aNiche().id(dto.getNicheId()).projectId(entity.getId())
.enabled(String.valueOf(StateEnum.DISABLE.getValue())).build());
}
return MapUtil.<String, String>builder().put(BUSINESS_KEY, entity.getId())
.put(SERVICE_NAME, ServiceNameEnum.projectService.getValue()).build();
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// 只能释放自己的锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
然后生成的code总是有重复的,加日志加日志
longcoming-oa: 2024-07-27 12:53:13.595 INFO 141708 [http-nio-7077-exec-32] c.l.oa.service.impl.ProjectServiceImpl : thread: 300, getcode: DBHLJ-202407-1873
longcoming-oa: 2024-07-27 12:53:13.595 INFO 141708 [http-nio-7077-exec-32] c.l.oa.service.impl.ProjectServiceImpl : thread: 300, setcode: DBHLJ-202407-1874
longcoming-oa: 2024-07-27 12:53:13.619 INFO 141708 [http-nio-7077-exec-32] c.l.oa.service.impl.ProjectServiceImpl : unLock: 300
longcoming-oa: 2024-07-27 12:53:13.624 INFO 141708 [http-nio-7077-exec-35] c.l.oa.service.impl.ProjectServiceImpl : getLock: 305
longcoming-oa: 2024-07-27 12:53:13.632 INFO 141708 [http-nio-7077-exec-35] c.l.oa.service.impl.ProjectServiceImpl : thread: 305, getcode: DBHLJ-202407-1874
longcoming-oa: 2024-07-27 12:53:13.632 INFO 141708 [http-nio-7077-exec-35] c.l.oa.service.impl.ProjectServiceImpl : thread: 305, setcode: DBHLJ-202407-1875
longcoming-oa: 2024-07-27 12:53:13.652 INFO 141708 [http-nio-7077-exec-35] c.l.oa.service.impl.ProjectServiceImpl : unLock: 305
longcoming-oa: 2024-07-27 12:53:13.656 INFO 141708 [http-nio-7077-exec-27] c.l.oa.service.impl.ProjectServiceImpl : getLock: 284
longcoming-oa: 2024-07-27 12:53:13.667 INFO 141708 [http-nio-7077-exec-27] c.l.oa.service.impl.ProjectServiceImpl : thread: 284, getcode: DBHLJ-202407-1874
longcoming-oa: 2024-07-27 12:53:13.667 INFO 141708 [http-nio-7077-exec-27] c.l.oa.service.impl.ProjectServiceImpl : thread: 284, setcode: DBHLJ-202407-1875
longcoming-oa: 2024-07-27 12:53:13.696 INFO 141708 [http-nio-7077-exec-27] c.l.oa.service.impl.ProjectServiceImpl : unLock: 284
longcoming-oa: 2024-07-27 12:53:13.705 INFO 141708 [http-nio-7077-exec-29] c.l.oa.service.impl.ProjectServiceImpl : getLock: 296
longcoming-oa: 2024-07-27 12:53:13.716 INFO 141708 [http-nio-7077-exec-29] c.l.oa.service.impl.ProjectServiceImpl : thread: 296, getcode: DBHLJ-202407-1875
longcoming-oa: 2024-07-27 12:53:13.716 INFO 141708 [http-nio-7077-exec-29] c.l.oa.service.impl.ProjectServiceImpl : thread: 296, setcode: DBHLJ-202407-1876
锁是没有问题的,有理由怀疑是释放锁的时候事务还没有提交导致获取了重复的编号
改改改
@Override
public Map<String, String> saveEntity(ProjectApprovalDTO dto) {
// 判断行政区划和行政区域是否全部为中文
if (!Validator.isChinese(dto.getDirection()) || !Validator.isChinese(dto.getRegion())) {
throw new GlobalBadRequestException("");
}
RLock lock = redisson.getLock("generateCode");
boolean tryLock;
try {
tryLock = lock.tryLock(5, TimeUnit.SECONDS);
if (!tryLock) {
throw new GlobalBadRequestException("");
}
return generateCodeAndSave(dto);
} catch (InterruptedException e) {
log.error("ProjectServiceImpl occurs error", e);
throw new GlobalBadRequestException(LOCK_FAILED);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
@Transactional(rollbackFor = Exception.class)
public Map<String, String> generateCodeAndSave(ProjectApprovalDTO dto) {
ProjectApproval projectApproval = convert.toEntity(dto);
StringBuilder sb = new StringBuilder();
// 取行政区划 行政区域 拼音首字母
sb.append(StrUtil.swapCase(PinyinUtil.getFirstLetter(projectApproval.getDirection(), StrUtil.EMPTY)))
.append(StrUtil.swapCase(PinyinUtil.getFirstLetter(projectApproval.getRegion(), StrUtil.EMPTY)))
.append(StringPool.DASH).append(DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN))
.append(StringPool.DASH);
ProjectApproval projectMaxCode = projectApprovalMapper.findLastedCode(sb.toString());
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumIntegerDigits(4);
formatter.setGroupingUsed(false);
long num = 1;
if (!ObjectUtil.isEmpty(projectMaxCode)) {
String[] split = projectMaxCode.getCode().split(StringPool.DASH);
String s = split[split.length - 1];
num += Integer.parseInt(s);
}
sb.append(formatter.format(num));
projectApproval.setCode(sb.toString());
if (save(projectApproval) && !StrUtil.isEmpty(dto.getNicheId())) {
nicheService.updateById(Niche.Builder.aNiche().id(dto.getNicheId()).projectId(projectApproval.getId())
.enabled(String.valueOf(StateEnum.DISABLE.getValue())).build());
}
return MapUtil.<String, String>builder().put(BUSINESS_KEY, projectApproval.getId())
.put(SERVICE_NAME, ServiceNameEnum.projectService.getValue()).build();
}
问题解决啦