Ver código fonte

智能批改后端修复

lzzz 7 meses atrás
pai
commit
6fa9bcade0

+ 59 - 33
src/main/java/com/njuzr/eaibackend/service/AIEvaluationService.java

@@ -15,6 +15,9 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
+import org.springframework.transaction.TransactionDefinition;
 
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
@@ -45,6 +48,8 @@ public class AIEvaluationService {
 
     private final EvaluationMapperServiceImpl evaluationMapperServiceImpl;
 
+    private final TransactionTemplate requiresNewTransactionTemplate;
+
     @Autowired
     @Qualifier("aiTaskExecutor")
     private ThreadPoolTaskExecutor aiTaskExecutor;
@@ -56,7 +61,11 @@ public class AIEvaluationService {
     private SentenceEvaluationMapperServiceImpl sentenceEvaluationMapperServiceImpl;
 
     @Autowired
-    public AIEvaluationService(AIRequestService aiRequestService, StudentAssignmentMapper studentAssignmentMapper, AssignmentMapper assignmentMapper, OverallEvaluationMapper overallEvaluationMapper, SentenceEvaluationMapper sentenceEvaluationMapper, EvaluationMapper evaluationMapper, EvaluationMapperServiceImpl evaluationMapperServiceImpl) {
+    public AIEvaluationService(AIRequestService aiRequestService, StudentAssignmentMapper studentAssignmentMapper,
+            AssignmentMapper assignmentMapper, OverallEvaluationMapper overallEvaluationMapper,
+            SentenceEvaluationMapper sentenceEvaluationMapper, EvaluationMapper evaluationMapper,
+            EvaluationMapperServiceImpl evaluationMapperServiceImpl,
+            PlatformTransactionManager transactionManager) {
         this.aiRequestService = aiRequestService;
         this.studentAssignmentMapper = studentAssignmentMapper;
         this.assignmentMapper = assignmentMapper;
@@ -64,6 +73,10 @@ public class AIEvaluationService {
         this.sentenceEvaluationMapper = sentenceEvaluationMapper;
         this.evaluationMapper = evaluationMapper;
         this.evaluationMapperServiceImpl = evaluationMapperServiceImpl;
+
+        // 创建一个使用REQUIRES_NEW传播行为的TransactionTemplate,确保每次都在新事务中执行
+        this.requiresNewTransactionTemplate = new TransactionTemplate(transactionManager);
+        this.requiresNewTransactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
     }
 
     public CompletableFuture<AIEntry> evaluationAsync(Long assignmentId, Long studentId) {
@@ -71,7 +84,7 @@ public class AIEvaluationService {
                 .exceptionally(ex -> { throw new MyException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "AI请求失败:" + ex.getMessage());})
                 .orTimeout(40, TimeUnit.SECONDS);
     }
-    
+
     /**
      * AI作文整体智能批改
      * @param assignmentId
@@ -81,34 +94,23 @@ public class AIEvaluationService {
      */
     public AIEntry evaluation(Long assignmentId, Long studentId) {
         StopWatch sw = StopWatch.createStarted();
+        Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
+        if(engagement == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业参与不存在");
+        Assignment assignment = assignmentMapper.selectById(assignmentId);
+        if (assignment == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
+        Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
+        if(evaluationJudge != null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
+        // 先在独立事务中初始化记录,确保其他线程能立即查询到
+        initEvaluationRecord(assignmentId, studentId, engagement);
         try{
-            Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
-            if(engagement == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业参与不存在");
-            Assignment assignment = assignmentMapper.selectById(assignmentId);
-            if (assignment == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
-            Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
-            if(evaluationJudge != null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
-            initEvaluationRecord(assignmentId, studentId, engagement);
-
             // 发起LLM请求
             String prompt = String.format(PromptConstant.REWRITE_PROMPT_TEMPLATE, assignment.getDescription(), engagement.getTextContent());
             AIRequestService.AIResponse response = requestAIWithRetry(prompt, 0);
             String retContent = response.getChoices().get(0).getMessage().getContent();
             String role = response.getChoices().get(0).getMessage().getRole();
 
-            OverallEvaluation overallEvaluation = new OverallEvaluation()
-                .setStudentId(studentId)
-                .setAssignmentId(assignmentId)
-                .setContent(engagement.getTextContent())
-                .setEvaluation(retContent)
-                .setVersion(engagement.getVersion());
-            overallEvaluationMapper.insert(overallEvaluation);
-
-            evaluationMapperServiceImpl.update(new UpdateWrapper<Evaluation>()
-                    .set("overall", 1)
-                    .eq("student_id", studentId)
-                    .eq("assignment_id", assignmentId)
-                    .eq("version", engagement.getVersion()));
+            // 保存评估结果
+            saveOverallEvaluationResult(assignmentId, studentId, engagement, retContent);
 
             log.info("evaluation cost: {}", sw.formatTime());
             return new AIEntry(role, retContent);
@@ -120,16 +122,36 @@ public class AIEvaluationService {
     }
 
     private void initEvaluationRecord(Long assignmentId, Long studentId, Engagement engagement) {
-        Evaluation evaluation = new Evaluation()
-            .setTime(new Date())
-            .setAssignmentId(assignmentId)
+        // 使用编程式事务,确保记录立即提交,其他线程能够查询到
+        requiresNewTransactionTemplate.executeWithoutResult(status -> {
+            Evaluation evaluation = new Evaluation()
+                .setTime(new Date())
+                .setAssignmentId(assignmentId)
+                .setStudentId(studentId)
+                .setVersion(engagement.getVersion())
+                .setSentence(0)
+                .setOverall(0);
+            evaluationMapperServiceImpl.save(evaluation);
+            log.info("evaluation record init");
+            log.info("evaluation record: {}", evaluation);
+        });
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void saveOverallEvaluationResult(Long assignmentId, Long studentId, Engagement engagement, String retContent) {
+        OverallEvaluation overallEvaluation = new OverallEvaluation()
             .setStudentId(studentId)
-            .setVersion(engagement.getVersion())
-            .setSentence(0)
-            .setOverall(0);
-        evaluationMapperServiceImpl.save(evaluation);
-        log.info("evaluation record init");
-        log.info("evaluation record: {}", evaluation);
+            .setAssignmentId(assignmentId)
+            .setContent(engagement.getTextContent())
+            .setEvaluation(retContent)
+            .setVersion(engagement.getVersion());
+        overallEvaluationMapper.insert(overallEvaluation);
+
+        evaluationMapperServiceImpl.update(new UpdateWrapper<Evaluation>()
+                .set("overall", 1)
+                .eq("student_id", studentId)
+                .eq("assignment_id", assignmentId)
+                .eq("version", engagement.getVersion()));
     }
 
     private AIRequestService.AIResponse requestAIWithRetry(String prompt, int retryTime) {
@@ -159,9 +181,13 @@ public class AIEvaluationService {
         if (assignment == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
 
         // 没有智能评价记录时,进行重试,等待整体智能批改将记录写入数据库
+        // 使用编程式事务在新事务中查询,避免REPEATABLE READ隔离级别导致看不到其他事务提交的数据
         int retryTime = 0;
         while (retryTime < 3) {
-            Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
+            final int currentVersion = engagement.getVersion();
+            Evaluation evaluationJudge = requiresNewTransactionTemplate.execute(status ->
+                evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, currentVersion)
+            );
             log.info("rewritePerSentence find evaluation record, assignmentId: {}, studentId: {}, version: {}", assignmentId, studentId, engagement.getVersion());
             if (evaluationJudge == null){
                 try {