diff --git a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/EnrollmentPlanCompletionAdapter.java b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/EnrollmentPlanCompletionAdapter.java index 7ffbf910e..62c3fda4a 100644 --- a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/EnrollmentPlanCompletionAdapter.java +++ b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/EnrollmentPlanCompletionAdapter.java @@ -41,6 +41,10 @@ public class EnrollmentPlanCompletionAdapter implements PlanEnrollmentCompletion @Override public void precheckCompletion(String planId) { + // 按 enrollment_id 稳定升序锁定该计划下全部学员记录 (SELECT ... ORDER BY enrollment_id FOR UPDATE), + // 阻止结训与学员报到/状态修改之间的并发竞态与 TOCTOU 窗口 + trainEnrollmentService.selectEnrollmentsForUpdateByPlanId(planId); + List> stats = trainEnrollmentService.selectEnrollmentCompletionStatsByPlanId(planId); int status0Waiting = 0; int status1Reported = 0;