From 01eaacc32c18faf1472230605ec5bfe3ec086151 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Wed, 5 Aug 2026 09:41:25 +0800 Subject: [PATCH] fix: prevent duplicate score ranks --- .../service/impl/ScoreRankServiceImpl.java | 7 ++++--- .../ScoreRankServiceImplTeachingClassTest.java | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImpl.java index faaee0d..3cd73c6 100644 --- a/src/main/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImpl.java +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImpl.java @@ -53,7 +53,7 @@ public class ScoreRankServiceImpl implements ScoreRankService { @Override @Scheduled(cron = "0 0 1 * * ?") - public Boolean doRank() { + public synchronized Boolean doRank() { ensureStuRankIndexes(); if (schoolClassMapper != null) { SchoolClassExample teachingClassExample = new SchoolClassExample(); @@ -176,7 +176,7 @@ public class ScoreRankServiceImpl implements ScoreRankService { @Override - public Boolean doRankOne(String schoolId) { + public synchronized Boolean doRankOne(String schoolId) { ensureStuRankIndexes(); StuRankExample stuRankExample = new StuRankExample(); stuRankExample.createCriteria().andUpdateTimeEqualTo(getNowDate()).andSchoolIdEqualTo(schoolId); @@ -198,7 +198,7 @@ public class ScoreRankServiceImpl implements ScoreRankService { } @Override - public Boolean doRankTeachingClass(String schoolId, String teachingClassId) { + public synchronized Boolean doRankTeachingClass(String schoolId, String teachingClassId) { ensureStuRankIndexes(); SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); if (teachingClass == null || !"TEACHING".equals(teachingClass.getClassType())) { @@ -439,6 +439,7 @@ public class ScoreRankServiceImpl implements ScoreRankService { } addIndexIfMissing("idx_stu_rank_update_school", "ALTER TABLE stu_rank ADD INDEX idx_stu_rank_update_school (update_time, school_id)"); addIndexIfMissing("idx_stu_rank_update_class", "ALTER TABLE stu_rank ADD INDEX idx_stu_rank_update_class (update_time, school_class_id)"); + addIndexIfMissing("uq_stu_rank_update_class_user", "ALTER TABLE stu_rank ADD UNIQUE INDEX uq_stu_rank_update_class_user (update_time, school_class_id, user_id)"); stuRankIndexesChecked = true; } } diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImplTeachingClassTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImplTeachingClassTest.java index 5f0f324..c4ccc94 100644 --- a/src/test/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImplTeachingClassTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImplTeachingClassTest.java @@ -26,6 +26,8 @@ import com.sztzjy.linkCommerce.mapper.WeightMapper; import com.sztzjy.linkCommerce.service.SchoolDefaultTaskService; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.util.Arrays; @@ -40,6 +42,19 @@ import static org.mockito.Mockito.when; class ScoreRankServiceImplTeachingClassTest { + @Test + void rankIndexesIncludeUniqueConstraintForDailyTeachingClassStudent() { + ScoreRankServiceImpl service = new ScoreRankServiceImpl(); + service.jdbcTemplate = mock(JdbcTemplate.class); + + ReflectionTestUtils.invokeMethod(service, "ensureStuRankIndexes"); + + ArgumentCaptor ddlCaptor = ArgumentCaptor.forClass(String.class); + verify(service.jdbcTemplate, org.mockito.Mockito.atLeastOnce()).execute(ddlCaptor.capture()); + assertTrue(ddlCaptor.getAllValues().stream().anyMatch(ddl -> ddl.contains( + "ADD UNIQUE INDEX uq_stu_rank_update_class_user (update_time, school_class_id, user_id)"))); + } + @Test void doRankTeachingClassUsesTeachingClassMembersOnly() { ScoreRankServiceImpl service = serviceWithMocks();