فهرست منبع

评卷任务提交增加强制校验

1.评卷员增加串行准入锁
2.当前评卷任务增加数据库行锁
3.事物内重复校验评卷任务有效性
luoshi 6 سال پیش
والد
کامیت
b1fe9b689a

+ 12 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java

@@ -4,9 +4,12 @@ import java.util.Date;
 import java.util.List;
 import java.util.Set;
 
+import javax.persistence.LockModeType;
+
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Lock;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
@@ -15,6 +18,9 @@ import cn.com.qmth.stmms.common.enums.LibraryStatus;
 
 public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, JpaSpecificationExecutor<MarkLibrary> {
 
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    MarkLibrary findByIdForLock(Integer id);
+
     List<MarkLibrary> findByExamId(Integer examId, Pageable page);
 
     List<MarkLibrary> findByExamIdAndSubjectCode(Integer examId, String subjectCode, Pageable page);
@@ -42,6 +48,9 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     @Query("select count(*) from MarkLibrary f where f.studentId=?1 and f.markerId=?2")
     long countByStudentIdAndMarkerId(Integer studentId, Integer markerId);
 
+    @Query("select count(*) from MarkLibrary f where f.studentId=?1 and f.markerId=?2 and f.id!=?3")
+    long countByStudentIdAndMarkerIdAndIdNotEqual(Integer studentId, Integer markerId, Integer id);
+
     @Query("select distinct l.campusId from MarkLibrary l where l.examId=?1 and l.tags is not null")
     List<Integer> findTagCampusId(Integer examId);
 
@@ -69,6 +78,9 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     @Query("select count(*) from MarkLibrary f where f.examId=?1 and f.subjectCode=?2 and f.status=?3")
     long countByExamIdAndSubjectCodeAndStatus(Integer examId, String subjectCode, LibraryStatus status);
 
+    @Query("select count(*) from MarkLibrary f where f.id=?1 and f.markerId=?2 and f.status=?3")
+    long countByIdAndMarkerIdAndStatus(Integer id, Integer markerId, LibraryStatus status);
+
     @Query("select f.markerId, count(*) as markerCount from MarkLibrary f where f.examId=?1 and f.status=?2 group by f.markerId")
     List<Object[]> countByMarkerAndStatus(Integer examId, LibraryStatus status);
 

+ 39 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkLockService.java

@@ -27,6 +27,8 @@ public class MarkLockService {
 
     private Map<Object, AtomicBoolean> studentMap = new HashMap<>();
 
+    private Map<Object, AtomicBoolean> markerMap = new HashMap<>();
+
     /**
      * 对评卷分组进行重置/删除操作前,先尝试锁定
      * 
@@ -99,9 +101,46 @@ public class MarkLockService {
         }
     }
 
+    /**
+     * 评卷员进行评卷操作前,先尝试锁定
+     * 
+     * @param markerId
+     */
+    public void lockMarker(Integer markerId) {
+        AtomicBoolean lock = getLock(markerMap, markerId);
+        while (!lock.get()) {
+            lock.compareAndSet(false, true);
+        }
+    }
+
+    /**
+     * 评卷员进行评卷操作后,释放锁定
+     * 
+     * @param markerId
+     */
+    public void unlockMarker(Integer markerId) {
+        AtomicBoolean lock = getLock(markerMap, markerId);
+        while (lock.get()) {
+            lock.compareAndSet(true, false);
+        }
+    }
+
+    /**
+     * 等待评卷员释放锁定
+     * 
+     * @param studentId
+     */
+    public void waitUnlockMarker(Integer markerId) {
+        AtomicBoolean lock = getLock(markerMap, markerId);
+        while (lock.get()) {
+            ;
+        }
+    }
+
     public void clear() {
         clearLock(groupMap);
         clearLock(studentMap);
+        clearLock(markerMap);
     }
 
     private void clearLock(Map<Object, AtomicBoolean> map) {

+ 73 - 49
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java

@@ -194,7 +194,7 @@ public class MarkServiceImpl implements MarkService {
             subjectService.updateScore(group.getExamId(), group.getSubjectCode());
             resetGroup(group);
         } catch (Exception e) {
-        	e.printStackTrace();
+            e.printStackTrace();
             throw e;
         } finally {
             lockService.unlockGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
@@ -300,57 +300,81 @@ public class MarkServiceImpl implements MarkService {
         lockService.waitUnlockGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
         // 等待考生释放锁定
         lockService.waitUnlockStudent(library.getStudentId());
-        // 若该评卷任务已被删除,则直接返回
-        if (!libraryDao.exists(library.getId())) {
-            return;
-        }
-        // 保存阅卷轨迹
-        if (trackList != null) {
-            trackDao.deleteByLibraryId(library.getId());
-            trackDao.save(trackList);
-        }
-        // 保存特殊标记
-        if (tagList != null) {
-            specialTagDao.deleteByLibraryId(library.getId());
-            specialTagDao.save(tagList);
-        }
 
-        ArbitrateHistory history = null;
-        if (group.getArbitrateThreshold() != null && group.getArbitrateThreshold() > 0) {
-            // 多评模式
-            List<MarkLibrary> list = libraryDao.findByStudentIdAndGroupNumber(library.getStudentId(),
-                    library.getGroupNumber());
-            for (MarkLibrary other : list) {
-                if (other.getId().equals(library.getId()) || other.getStatus() != LibraryStatus.MARKED
-                        || other.getMarkerScore() == null || other.getHeaderScore() != null) {
-                    // 未评卷或组长已打分,则跳过该任务
-                    continue;
-                }
-                if (Math.abs(other.getMarkerScore() - library.getMarkerScore()) > group.getArbitrateThreshold()) {
-                    // 分差超过阀值,触发仲裁
-                    history = new ArbitrateHistory();
-                    history.setExamId(library.getExamId());
-                    history.setSubjectCode(library.getSubjectCode());
-                    history.setGroupNumber(library.getGroupNumber());
-                    history.setStudentId(library.getStudentId());
-                    history.setExamNumber(library.getExamNumber());
-                    history.setStatus(HistoryStatus.WAITING);
-                    history.setCreateTime(new Date());
-                    arbitrateDao.save(history);
-
-                    library.setStatus(LibraryStatus.WAIT_ARBITRATE);
-                    break;
+        try {
+            // 尝试锁定评卷员
+            lockService.lockMarker(library.getMarkerId());
+            // 锁定该评卷任务
+            MarkLibrary previous = libraryDao.findByIdForLock(library.getId());
+            // 若该评卷任务已被删除,则直接返回
+            if (previous == null) {
+                return;
+            }
+            // 该评卷任务已被别人评过,也直接返回
+            if (previous.getMarkerId() != null && !previous.getMarkerId().equals(library.getMarkerId())) {
+                return;
+            }
+            // 该评卷任务状态不是已评或未评,也直接返回
+            if (previous.getStatus() != LibraryStatus.WAITING && previous.getStatus() != LibraryStatus.MARKED) {
+                return;
+            }
+            // 已经评过该考生的其他评卷任务,则直接返回
+            if (libraryDao.countByStudentIdAndMarkerIdAndIdNotEqual(library.getStudentId(), library.getMarkerId(),
+                    library.getId()) > 0) {
+                return;
+            }
+            // 保存阅卷轨迹
+            if (trackList != null) {
+                trackDao.deleteByLibraryId(library.getId());
+                trackDao.save(trackList);
+            }
+            // 保存特殊标记
+            if (tagList != null) {
+                specialTagDao.deleteByLibraryId(library.getId());
+                specialTagDao.save(tagList);
+            }
+            // 判断多评模式下是否需要仲裁
+            ArbitrateHistory history = null;
+            if (group.getArbitrateThreshold() != null && group.getArbitrateThreshold() > 0) {
+                // 多评模式
+                List<MarkLibrary> list = libraryDao.findByStudentIdAndGroupNumber(library.getStudentId(),
+                        library.getGroupNumber());
+                for (MarkLibrary other : list) {
+                    if (other.getId().equals(library.getId()) || other.getStatus() != LibraryStatus.MARKED
+                            || other.getMarkerScore() == null || other.getHeaderScore() != null) {
+                        // 未评卷或组长已打分,则跳过该任务
+                        continue;
+                    }
+                    if (Math.abs(other.getMarkerScore() - library.getMarkerScore()) > group.getArbitrateThreshold()) {
+                        // 分差超过阀值,触发仲裁
+                        history = new ArbitrateHistory();
+                        history.setExamId(library.getExamId());
+                        history.setSubjectCode(library.getSubjectCode());
+                        history.setGroupNumber(library.getGroupNumber());
+                        history.setStudentId(library.getStudentId());
+                        history.setExamNumber(library.getExamNumber());
+                        history.setStatus(HistoryStatus.WAITING);
+                        history.setCreateTime(new Date());
+                        arbitrateDao.save(history);
+
+                        library.setStatus(LibraryStatus.WAIT_ARBITRATE);
+                        break;
+                    }
                 }
             }
-        }
-        library = libraryDao.saveAndFlush(library);
-        // 触发仲裁后续处理
-        if (history != null) {
-            libraryDao.updateByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber(),
-                    LibraryStatus.WAIT_ARBITRATE);
-        } else if (library.getStatus() == LibraryStatus.MARKED) {
-            // 评卷正常完成才尝试统分
-            scoreCalculate(library.getExamId(), library.getSubjectCode(), library.getStudentId());
+            library = libraryDao.saveAndFlush(library);
+            // 触发仲裁后续处理
+            if (history != null) {
+                libraryDao.updateByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber(),
+                        LibraryStatus.WAIT_ARBITRATE);
+            } else if (library.getStatus() == LibraryStatus.MARKED) {
+                // 评卷正常完成才尝试统分
+                scoreCalculate(library.getExamId(), library.getSubjectCode(), library.getStudentId());
+            }
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            lockService.unlockMarker(library.getMarkerId());
         }
     }