From 1ec42f4ad55c1aa18d73eafbd59bdd28082ec122 Mon Sep 17 00:00:00 2001 From: litianxiang Date: Wed, 4 Feb 2026 17:20:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E5=8F=82=E8=B5=9B=E8=80=85id=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/GlobalAwardServiceImpl.java | 82 ++++++++++++------- .../primary/WorkspaceRelStyleMapper.xml | 1 + 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java b/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java index 948529d6..e474cb79 100644 --- a/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java @@ -158,34 +158,59 @@ public class GlobalAwardServiceImpl implements GlobalAwardService { LocalDateTime now = LocalDateTime.now(); if (existing == null) { - // 由数据库自增分配 contestant_number(请确保数据库列为 AUTO_INCREMENT) - Contestant toInsert = Contestant.builder() - .email(request.getEmail()) - .firstName(request.getFirstName()) - .lastName(request.getLastName()) - .gender(request.getGender()) - .occupation(request.getOccupation()) - .age(request.getAge()) - .countryRegionCity(request.getCountryRegionCity()) - .phoneNumber(request.getPhoneNumber()) - .designTitle(request.getDesignTitle()) - .designDescription(request.getDesignDescription()) - .pdfPath(request.getPdfPath()) - .videoPath(request.getVideoPath()) - .videoDuration(request.getVideoDuration()) - .videoSize(request.getVideoSize()) - .pdfSize(request.getPdfSize()) - .createdAt(now) - .updatedAt(now) - .build(); - contestantMapper.insert(toInsert); - // 重新查询以获取数据库分配的 contestant_number - Contestant saved = contestantMapper.selectById(toInsert.getId()); - Integer assignedNumber = (saved == null) ? null : saved.getContestantNumber(); - resp.put("success", true); - resp.put("contestant_number", assignedNumber); - sendSiteMsg(toInsert.getId(), toInsert.getEmail()); - return resp; + // 通过行锁 + 重试机制保证 contestant_number 在并发下自增分配 + final int maxAttempts = 5; + for (int attempt = 1; attempt <= maxAttempts; attempt++) { + try { + // 获取当前最大 contestant_number 并加行锁(LIMIT 1 FOR UPDATE) + QueryWrapper qMax = new QueryWrapper<>(); + qMax.isNotNull("contestant_number"); + qMax.orderByDesc("contestant_number"); + qMax.last("LIMIT 1 FOR UPDATE"); + Contestant last = contestantMapper.selectOne(qMax); + Integer nextNumber = (last == null || last.getContestantNumber() == null) ? 10000 : last.getContestantNumber() + 1; + + Contestant toInsert = Contestant.builder() + .email(request.getEmail()) + .firstName(request.getFirstName()) + .lastName(request.getLastName()) + .gender(request.getGender()) + .occupation(request.getOccupation()) + .age(request.getAge()) + .countryRegionCity(request.getCountryRegionCity()) + .phoneNumber(request.getPhoneNumber()) + .designTitle(request.getDesignTitle()) + .designDescription(request.getDesignDescription()) + .pdfPath(request.getPdfPath()) + .videoPath(request.getVideoPath()) + .videoDuration(request.getVideoDuration()) + .videoSize(request.getVideoSize()) + .pdfSize(request.getPdfSize()) + .contestantNumber(nextNumber) + .createdAt(now) + .updatedAt(now) + .build(); + + contestantMapper.insert(toInsert); + + resp.put("success", true); + sendSiteMsg(toInsert.getId(), toInsert.getEmail()); + return resp; + } catch (Exception e) { + log.warn("Attempt {} to assign contestant_number failed", attempt, e); + String msg = e.getMessage() == null ? "" : e.getMessage().toLowerCase(); + if ((msg.contains("duplicate") || msg.contains("uniq_contestant_number") || msg.contains("contestant_number")) && attempt < maxAttempts) { + try { + Thread.sleep(100L); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + continue; + } + throw e; + } + } + throw new BusinessException("Failed to assign contestant number after retries."); } else { // update existing contestant existing.setFirstName(request.getFirstName()); @@ -205,7 +230,6 @@ public class GlobalAwardServiceImpl implements GlobalAwardService { existing.setUpdatedAt(now); contestantMapper.updateById(existing); resp.put("success", true); - resp.put("contestant_number", existing.getContestantNumber()); return resp; } } diff --git a/src/main/resources/mapper/primary/WorkspaceRelStyleMapper.xml b/src/main/resources/mapper/primary/WorkspaceRelStyleMapper.xml index 03fbe225..754d40d8 100644 --- a/src/main/resources/mapper/primary/WorkspaceRelStyleMapper.xml +++ b/src/main/resources/mapper/primary/WorkspaceRelStyleMapper.xml @@ -18,3 +18,4 @@ +