Bläddra i källkod

机构版-迭代

xiaof 3 år sedan
förälder
incheckning
833b27c5df

+ 1 - 0
sql/msyj-org-20210628.sql

@@ -281,6 +281,7 @@ CREATE TABLE `mark_task`  (
   INDEX `idx_mark_task_paper_id`(`paper_id`) USING BTREE,
   INDEX `question_id`(`question_id`, `marker_id`, `stage`, `result`, `is_rejected`, `random_seq`, `random_seq_new`) USING BTREE,
   INDEX `idx_union_1`(`marker_id`, `stage`, `result`, `random_seq`, `random_seq_new`) USING BTREE,
+  INDEX `idx_rejected`(`is_rejected`) USING BTREE,
   CONSTRAINT `FKa6xqlu9ml2e47x1o2u2yec7vm` FOREIGN KEY (`paper_id`) REFERENCES `paper` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
   CONSTRAINT `mark_task_ibfk_1` FOREIGN KEY (`paper_id`) REFERENCES `paper` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
   CONSTRAINT `mark_task_ibfk_10` FOREIGN KEY (`paper_id`) REFERENCES `paper` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

+ 1 - 1
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/api/AuthApi.java

@@ -74,7 +74,7 @@ public class AuthApi {
 
         if (Objects.equals(Role.MARKER, domain.getRole())) {
             MarkSubject markSubject = markSubjectRepo.findOne(domain.getWorkId() + "-" + domain.getSubject().name());
-            List<MarkTask> markTasks = markTaskRepo.findByWorkIdAndSubjectAndMarkerIdAndStage(domain.getWorkId(), domain.getSubject().name(), domain.getId(), markSubject.getStage().ordinal());
+            List<MarkTask> markTasks = markTaskRepo.findByWorkIdAndSubjectAndMarkerIdAndStageLimit(domain.getWorkId(), domain.getSubject().name(), domain.getId(), markSubject.getStage().ordinal());
             if (CollectionUtils.isEmpty(markTasks)) {
                 throw new RuntimeException("没有评卷任务");
             }

+ 6 - 0
stmms-ms-commons/pom.xml

@@ -71,5 +71,11 @@
             <artifactId>aliyun-sdk-oss</artifactId>
             <version>3.8.0</version>
         </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.6</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>

+ 19 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/lock/LockProvider.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.stmms.ms.commons.lock;
+
+
+public interface LockProvider {
+
+    void waitLock(LockType type, String key);
+
+    boolean tryLock(LockType type, String key);
+
+    void unlock(LockType type, String key);
+
+    boolean isLocked(LockType type, String key);
+
+    void watch(LockType type, String key);
+
+    void unwatch(LockType type, String key);
+
+    void clear();
+}

+ 106 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/lock/LockService.java

@@ -0,0 +1,106 @@
+package cn.com.qmth.stmms.ms.commons.lock;
+
+import cn.com.qmth.stmms.ms.commons.lock.impl.CustomLockProvider;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component("lockService")
+public class LockService implements InitializingBean, ApplicationContextAware {
+
+    protected static final Logger log = LoggerFactory.getLogger(LockService.class);
+
+    private static final String KEY_JOINER = "\t";
+
+    private ApplicationContext context;
+
+    private LockProvider provider;
+
+    /**
+     * 尝试获取排他锁,立即返回获取结果
+     *
+     * @param type
+     * @param keys
+     * @return
+     */
+    public boolean trylock(LockType type, Object... keys) {
+        return provider.tryLock(type, getKeys(keys));
+    }
+
+    /**
+     * 等待获取排他锁,线程阻塞直到成功获取
+     *
+     * @param type
+     * @param keys
+     */
+    public void waitlock(LockType type, Object... keys) {
+        provider.waitLock(type, getKeys(keys));
+    }
+
+    /**
+     * 释放已获取的排他锁
+     *
+     * @param type
+     * @param keys
+     */
+    public void unlock(LockType type, Object... keys) {
+        provider.unlock(type, getKeys(keys));
+    }
+
+    /**
+     * 检测排他锁是否已被获取
+     *
+     * @param type
+     * @param keys
+     * @return
+     */
+    public boolean isLocked(LockType type, Object... keys) {
+        return provider.isLocked(type, getKeys(keys));
+    }
+
+    /**
+     * 等待获取可重入的读锁
+     *
+     * @param type
+     * @param keys
+     */
+    public void watch(LockType type, Object... keys) {
+        provider.watch(type, getKeys(keys));
+    }
+
+    /**
+     * 释放已获取的读锁
+     *
+     * @param type
+     * @param keys
+     */
+    public void unwatch(LockType type, Object... keys) {
+        provider.unwatch(type, getKeys(keys));
+    }
+
+    /**
+     * 释放长时间未使用的锁
+     */
+    public void clear() {
+        provider.clear();
+    }
+
+    private String getKeys(Object... keys) {
+        return StringUtils.join(keys, KEY_JOINER);
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.provider = this.context.getBean(CustomLockProvider.class);
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext context) throws BeansException {
+        this.context = context;
+    }
+}

+ 16 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/lock/LockType.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.stmms.ms.commons.lock;
+
+public enum LockType {
+    LEVEL("level"), SCORE("score");
+
+    private String name;
+
+    private LockType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+}

+ 99 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/lock/impl/CustomLockProvider.java

@@ -0,0 +1,99 @@
+package cn.com.qmth.stmms.ms.commons.lock.impl;
+
+import cn.com.qmth.stmms.ms.commons.lock.LockProvider;
+import cn.com.qmth.stmms.ms.commons.lock.LockType;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * 自己实现的内存锁控制
+ *
+ * @author luoshi
+ */
+@Component("customLockProvider")
+public class CustomLockProvider implements LockProvider {
+
+    private Map<LockType, Map<String, ReadWriteLock>> lockMap = new HashMap<>();
+
+    @Override
+    public void waitLock(LockType type, String key) {
+        getLock(type, key).write();
+    }
+
+    @Override
+    public boolean tryLock(LockType type, String key) {
+        return getLock(type, key).tryWrite();
+    }
+
+    @Override
+    public boolean isLocked(LockType type, String key) {
+        return getLock(type, key).writing();
+    }
+
+    @Override
+    public void unlock(LockType type, String key) {
+        getLock(type, key).unWrite();
+    }
+
+    @Override
+    public void watch(LockType type, String key) {
+        getLock(type, key).read();
+    }
+
+    @Override
+    public void unwatch(LockType type, String key) {
+        getLock(type, key).unRead();
+    }
+
+    private ReadWriteLock getLock(LockType type, String key) {
+        Map<String, ReadWriteLock> map = lockMap.get(type);
+        if (map == null) {
+            synchronized (lockMap) {
+                map = lockMap.get(type);
+                if (map == null) {
+                    map = new HashMap<>();
+                    lockMap.put(type, map);
+                }
+            }
+        }
+
+        ReadWriteLock lock = map.get(key);
+        if (lock == null) {
+            synchronized (map) {
+                lock = map.get(key);
+                if (lock == null) {
+                    lock = new ReadWriteLock();
+                    map.put(key, lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    public void clear() {
+        if (lockMap.isEmpty()) {
+            return;
+        }
+        synchronized (lockMap) {
+            for (Map<String, ReadWriteLock> map : lockMap.values()) {
+                Set<String> keys = new HashSet<>();
+                for (Entry<String, ReadWriteLock> entry : map.entrySet()) {
+                    if (!entry.getValue().writing() && entry.getValue().readCount() == 0) {
+                        keys.add(entry.getKey());
+                    }
+                }
+                for (String key : keys) {
+                    map.remove(key);
+                }
+                keys.clear();
+            }
+        }
+    }
+
+}

+ 100 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/lock/impl/JdkLockProvider.java

@@ -0,0 +1,100 @@
+package cn.com.qmth.stmms.ms.commons.lock.impl;
+
+import cn.com.qmth.stmms.ms.commons.lock.LockProvider;
+import cn.com.qmth.stmms.ms.commons.lock.LockType;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * JVM内存实现的锁控制
+ *
+ * @author luoshi
+ */
+@Component("jdkLockProvider")
+public class JdkLockProvider implements LockProvider {
+
+    private Map<LockType, Map<String, ReentrantReadWriteLock>> lockMap = new HashMap<>();
+
+    @Override
+    public void waitLock(LockType type, String key) {
+        getLock(type, key).writeLock().lock();
+    }
+
+    @Override
+    public boolean tryLock(LockType type, String key) {
+        return getLock(type, key).writeLock().tryLock();
+    }
+
+    @Override
+    public boolean isLocked(LockType type, String key) {
+        return getLock(type, key).isWriteLocked();
+    }
+
+    @Override
+    public void unlock(LockType type, String key) {
+        getLock(type, key).writeLock().unlock();
+    }
+
+    @Override
+    public void watch(LockType type, String key) {
+        getLock(type, key).readLock().lock();
+    }
+
+    @Override
+    public void unwatch(LockType type, String key) {
+        getLock(type, key).readLock().unlock();
+    }
+
+    private ReentrantReadWriteLock getLock(LockType type, String key) {
+        Map<String, ReentrantReadWriteLock> map = lockMap.get(type);
+        if (map == null) {
+            synchronized (lockMap) {
+                map = lockMap.get(type);
+                if (map == null) {
+                    map = new HashMap<>();
+                    lockMap.put(type, map);
+                }
+            }
+        }
+
+        ReentrantReadWriteLock lock = map.get(key);
+        if (lock == null) {
+            synchronized (map) {
+                lock = map.get(key);
+                if (lock == null) {
+                    lock = new ReentrantReadWriteLock();
+                    map.put(key, lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    public void clear() {
+        if (lockMap.isEmpty()) {
+            return;
+        }
+        synchronized (lockMap) {
+            for (Map<String, ReentrantReadWriteLock> map : lockMap.values()) {
+                Set<String> keys = new HashSet<>();
+                for (Entry<String, ReentrantReadWriteLock> entry : map.entrySet()) {
+                    if (!entry.getValue().isWriteLocked() && entry.getValue().getReadLockCount() == 0) {
+                        keys.add(entry.getKey());
+                    }
+                }
+                for (String key : keys) {
+                    map.remove(key);
+                }
+                keys.clear();
+            }
+        }
+    }
+
+}

+ 135 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/lock/impl/ReadWriteLock.java

@@ -0,0 +1,135 @@
+package cn.com.qmth.stmms.ms.commons.lock.impl;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * 简单读写锁实现<br>
+ * 0表示空闲状态,-1表示正在写,>0表示正在读
+ * 
+ * @author luoshi
+ *
+ */
+public class ReadWriteLock {
+
+    private static ReadOperator readOperator = new ReadOperator();
+
+    private static UnReadOperator unreadOperator = new UnReadOperator();
+
+    private AtomicInteger value;
+
+    public ReadWriteLock() {
+        this.value = new AtomicInteger(0);
+    }
+
+    public int read() {
+        int result = 0;
+        while ((result = value.updateAndGet(readOperator)) < 1) {
+            ;
+        }
+        return result;
+    }
+
+    public int unRead() {
+        if (value.get() < 1) {
+            throw new RuntimeException("unread error");
+        }
+        return value.updateAndGet(unreadOperator);
+    }
+
+    public int readCount() {
+        return Math.max(0, value.get());
+    }
+
+    public int write() {
+        while (!value.compareAndSet(0, -1)) {
+            ;
+        }
+        return -1;
+    }
+
+    public boolean tryWrite() {
+        return value.compareAndSet(0, -1);
+    }
+
+    public int unWrite() {
+        while (!value.compareAndSet(-1, 0)) {
+            ;
+        }
+        return 0;
+    }
+
+    public boolean writing() {
+        return value.get() == -1;
+    }
+
+    static class ReadOperator implements IntUnaryOperator {
+
+        @Override
+        public int applyAsInt(int operand) {
+            return operand >= 0 ? operand + 1 : operand;
+        }
+
+    }
+
+    static class UnReadOperator implements IntUnaryOperator {
+
+        @Override
+        public int applyAsInt(int operand) {
+            return operand >= 1 ? operand - 1 : operand;
+        }
+
+    }
+
+    static class LockTestThread implements Runnable {
+
+        private ReadWriteLock lock;
+
+        private int number;
+
+        public LockTestThread(int number, ReadWriteLock lock) {
+            this.lock = lock;
+            this.number = number;
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < 10000; i++) {
+                if (Math.random() < 0.7) {
+                    System.out.println(
+                            "[thread-" + number + "]   read: " + lock.read() + "[" + System.currentTimeMillis() + "]");
+                    try {
+                        Thread.sleep(100 * ((i % 10) + 1));
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println("[thread-" + number + "] unread: " + lock.unRead() + "["
+                            + System.currentTimeMillis() + "]");
+                } else {
+                    System.out.println(
+                            "[thread-" + number + "]  write:" + lock.write() + "[" + System.currentTimeMillis() + "]");
+                    try {
+                        Thread.sleep(100 * ((i % 10) + 1));
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println("[thread-" + number + "]unwrite: " + lock.unWrite() + "["
+                            + System.currentTimeMillis() + "]");
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) {
+        ExecutorService executor = Executors.newFixedThreadPool(5);
+        final ReadWriteLock lock = new ReadWriteLock();
+        for (int i = 0; i < 5; i++) {
+            executor.submit(new LockTestThread(i + 1, lock));
+        }
+
+        executor.shutdown();
+    }
+
+}

+ 2 - 2
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/MD5Util.java

@@ -65,10 +65,10 @@ public class MD5Util {
         StringBuffer stringBuffer = new StringBuffer(String.valueOf(workId)).append(subjectId).append(areaCode).append(examNumber).append(studentId);
         String rule = stringBuffer.toString();
         LOGGER.info("rule:{},length:{}", rule, rule.length());
-        if (rule.length() < 16) {
+        /*if (rule.length() < 16) {
             rule = String.format("%016d", Long.parseLong(rule));
             LOGGER.info("rule补零后:{},length:{}", rule, rule.length());
-        }
+        }*/
         return encoder(rule);
     }
 }

+ 3 - 3
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkTaskRepo.java

@@ -229,7 +229,7 @@ public interface MarkTaskRepo extends JpaRepository<MarkTask, Long>, JpaSpecific
     int countByQuestionIdAndMarkerIdAndStageAndIsRejectedTrue(Long questionId, Long markerId, int ordinal);
 
     @Query(value = "select * from mark_task where work_id = ?1 and subject = ?2 and marker_id = ?3 and stage = ?4 limit 1", nativeQuery = true)
-    List<MarkTask> findByWorkIdAndSubjectAndMarkerIdAndStage(Long workId, String subject, Long valueOf, int stage);
+    List<MarkTask> findByWorkIdAndSubjectAndMarkerIdAndStageLimit(Long workId, String subject, Long valueOf, int stage);
 
     int countByWorkIdAndStageAndResultNotNull(Long id, MarkStage level);
 
@@ -240,10 +240,10 @@ public interface MarkTaskRepo extends JpaRepository<MarkTask, Long>, JpaSpecific
     @Query(value = "select count(1) from mark_task m inner join paper p on m.paper_id = p.id where m.work_id = ?1 and m.subject = ?2 and m.marker_id = ?3 and m.stage = ?4 and m.result is null and p.is_shift = true", nativeQuery = true)
     int countByWorkIdAndSubjectAndMarkerIdAndStageAndShiftAndResult(Long workId, String subject, Long valueOf, int stage);
 
-    @Query(value = "select count(1) from mark_task m inner join paper p on m.paper_id = p.id where m.work_id = ?1 and m.subject = ?2 and m.marker_id = ?3 and m.stage = ?4 and m.result is null and p.is_shift_score = 1", nativeQuery = true)
+    @Query(value = "select count(1) from mark_task m inner join (select id from paper where is_shift = 0 and is_shift_score = 1) p on m.paper_id = p.id where m.work_id = ?1 and m.subject = ?2 and m.marker_id = ?3 and m.stage = ?4 and m.result is null", nativeQuery = true)
     int countByWorkIdAndSubjectAndMarkerIdAndStageAndShiftScoreAndResult(Long workId, String subject, Long valueOf, int stage);
 
-    @Query(value = "select count(1) from mark_task m where m.work_id = ?1 and m.subject = ?2 and m.marker_id = ?3 and m.stage = ?4 and m.is_rejected = 1", nativeQuery = true)
+    @Query(value = "select count(1) from mark_task m where m.is_rejected = 1 and m.work_id = ?1 and m.subject = ?2 and m.marker_id = ?3 and m.stage = ?4 ", nativeQuery = true)
     int findByWorkIdAndSubjectAndMarkerIdAndStageReject(Long workId, String subject, Long valueOf, int stage);
 
     @Query(value = "select count(1) from mark_task m where m.work_id = ?1", nativeQuery = true)

+ 39 - 22
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MarkTaskApi.java

@@ -1,6 +1,8 @@
 package cn.com.qmth.stmms.ms.marking.api;
 
 import cn.com.qmth.stmms.ms.commons.config.ScoreConfig;
+import cn.com.qmth.stmms.ms.commons.lock.LockService;
+import cn.com.qmth.stmms.ms.commons.lock.LockType;
 import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
 import cn.com.qmth.stmms.ms.commons.web.PageableDTO;
 import cn.com.qmth.stmms.ms.core.cache.ParamCache;
@@ -11,7 +13,6 @@ import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
 import cn.com.qmth.stmms.ms.core.repository.*;
 import cn.com.qmth.stmms.ms.core.vo.Subject;
 import cn.com.qmth.stmms.ms.marking.assembler.MarkTaskAssembler;
-import cn.com.qmth.stmms.ms.marking.assembler.MarkerAssembler;
 import cn.com.qmth.stmms.ms.marking.assembler.PaperAssembler;
 import cn.com.qmth.stmms.ms.marking.dto.LevelDetailDTO;
 import cn.com.qmth.stmms.ms.marking.dto.MarkTaskDTO;
@@ -27,12 +28,10 @@ import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
-import org.springframework.orm.jpa.vendor.OpenJpaDialect;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
-import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.Join;
 import javax.persistence.criteria.JoinType;
 import javax.persistence.criteria.Predicate;
@@ -81,6 +80,9 @@ public class MarkTaskApi {
     @Autowired
     SqlUtil sqlUtil;
 
+    @Autowired
+    LockService lockService;
+
     /**
      * 评卷员的评卷任务
      *
@@ -108,15 +110,15 @@ public class MarkTaskApi {
         Long scoreBatchNo = null;
         if (stage == MarkStage.LEVEL) {
             List<Object> batchNos = paperRepo.findBatchNoByWorkIdAndSubject(workId, markUser.getSubject().name());
-            if(batchNos !=null && batchNos.size() > 0){
+            if (batchNos != null && batchNos.size() > 0) {
                 Object object = batchNos.get(0);
                 batchNo = Long.valueOf(object.toString());
             }
         } else if (stage == MarkStage.SCORE) {
             List<Object> batchNos = paperRepo.findScoreBatchNoByWorkIdAndSubject(workId, markUser.getSubject().name());
-            if(batchNos !=null && batchNos.size() > 0){
+            if (batchNos != null && batchNos.size() > 0) {
                 Object object = batchNos.get(0);
-                if(Objects.nonNull(object)) {
+                if (Objects.nonNull(object)) {
                     scoreBatchNo = Long.valueOf(object.toString());
                 }
             }
@@ -143,7 +145,7 @@ public class MarkTaskApi {
             } else if (stage == MarkStage.LEVEL) {
                 //查询
                 predicates.add(builder.equal(root.get("result"), level));
-                if(levelShowAllPaper  == 0) {
+                if (levelShowAllPaper == 0) {
                     if (!Objects.isNull(finalBatchNo)) {
                         onPredicates.add(builder.equal(join.get("batchNo"), finalBatchNo));
                     }
@@ -152,7 +154,7 @@ public class MarkTaskApi {
                 onPredicates.add(builder.equal(join.get("level"), level));
                 predicates.add(builder.isNotNull(root.get("result")));
                 onPredicates.add(builder.equal(join.get("isShift"), false));
-                if(scoreShowAllPaper  == 1){
+                if (scoreShowAllPaper == 1) {
                     onPredicates.add(builder.isNotNull(join.get("scoreBatchNo")));
                 } else {
                     onPredicates.add(builder.equal(join.get("scoreBatchNo"), finalScoreBatchNo));
@@ -174,7 +176,7 @@ public class MarkTaskApi {
             join.on(onPredicates.toArray(new Predicate[onPredicates.size()]));
             return builder.and(predicates.toArray(new Predicate[predicates.size()]));
         };
-        Sort sort = new Sort( "randomSeq", "randomSeqNew");
+        Sort sort = new Sort("randomSeq", "randomSeqNew");
         Pageable pageable1 = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), sort);
         Page<MarkTask> markTasks = markTaskRepo.findAll(specification, pageable1);
 
@@ -231,14 +233,14 @@ public class MarkTaskApi {
             if (isShift != null) {
                 //查询
                 predicates.add(builder.equal(root.get("paper").get("isShift"), isShift));
-                if(isShift){
+                if (isShift) {
                     predicates.add(builder.equal(root.get("stage"), MarkStage.LEVEL));
                     predicates.add(builder.isNull(root.get("result")));
                 }
             }
             if (isShiftScore != null && isShiftScore && !isShift) {
                 predicates.add(builder.equal(root.get("paper").get("isShiftScore"), isShiftScore));
-                if(isShiftScore){
+                if (isShiftScore) {
                     predicates.add(builder.equal(root.get("stage"), MarkStage.SCORE));
                     predicates.add(builder.isNull(root.get("result")));
                 }
@@ -262,10 +264,10 @@ public class MarkTaskApi {
      */
     @RequestMapping(value = "/manualScore", method = RequestMethod.GET)
     public PageableDTO listManualScore(@RequestParam Long markerId,
-                            @RequestParam(required = false) Long workId,
-                            @RequestParam Subject subject,
-                            @RequestParam Long questionId,
-                            Pageable pageable) {
+                                       @RequestParam(required = false) Long workId,
+                                       @RequestParam Subject subject,
+                                       @RequestParam Long questionId,
+                                       Pageable pageable) {
         List<MarkTaskDTO> markTaskDTOs = new ArrayList<>();
         Specification<MarkTask> specification = (root, query, builder) -> {
             List<Predicate> predicates = new ArrayList<>();
@@ -327,8 +329,13 @@ public class MarkTaskApi {
         }
         switch (stage) {
             case LEVEL:
-                synchronized (this) {
+                try {
+                    lockService.waitlock(LockType.LEVEL, markTask.getPaper().getId());
                     markingService.levelMark(markTask, result);
+                } catch (Exception e) {
+                    throw new RuntimeException("分档异常");
+                } finally {
+                    lockService.unlock(LockType.LEVEL, markTask.getPaper().getId());
                 }
                 break;
             case SCORE:
@@ -336,8 +343,13 @@ public class MarkTaskApi {
                 //是否手工输入分数
                 String manualScore = body.get("manualScore");
                 markTask.setManualScore(StringUtils.isEmpty(manualScore) ? 0 : Integer.parseInt(manualScore));
-                synchronized (this) {
+                try {
+                    lockService.waitlock(LockType.SCORE, markTask.getPaper().getId());
                     markingService.scoring(markTask, score);
+                } catch (Exception e) {
+                    throw new RuntimeException("打分异常");
+                } finally {
+                    lockService.unlock(LockType.SCORE, markTask.getPaper().getId());
                 }
                 break;
         }
@@ -347,7 +359,7 @@ public class MarkTaskApi {
     /**
      * 批量提交评卷任务
      *
-     * @param body     评卷内容
+     * @param body 评卷内容
      * @return
      */
     @RequestMapping(value = "batch", method = RequestMethod.PATCH)
@@ -355,7 +367,7 @@ public class MarkTaskApi {
         MarkStage stage = MarkStage.valueOf(body.get("stage"));
         String markIds = body.get("taskIds");
         String result = body.get("result");
-        if(Objects.isNull(markIds)){
+        if (Objects.isNull(markIds)) {
             throw new RuntimeException("请选择待评试卷");
         }
         String[] ids = markIds.split(",");
@@ -370,8 +382,13 @@ public class MarkTaskApi {
             }
             switch (stage) {
                 case LEVEL:
-                    synchronized (this) {
+                    try {
+                        lockService.waitlock(LockType.LEVEL, markTask.getPaper().getId());
                         markingService.levelMark(markTask, result);
+                    } catch (Exception e) {
+                        throw new RuntimeException("分档异常");
+                    } finally {
+                        lockService.unlock(LockType.LEVEL, markTask.getPaper().getId());
                     }
                     break;
                 case SCORE:
@@ -421,8 +438,8 @@ public class MarkTaskApi {
         Long socreBatchNo = null;
         if (stage == MarkStage.LEVEL) {
             batchNo = paperRepo.findByQuestionId(questionId);
-        }else if (stage == MarkStage.SCORE) {
-            socreBatchNo=paperRepo.findScoreBatchNoByQuestionId(questionId);
+        } else if (stage == MarkStage.SCORE) {
+            socreBatchNo = paperRepo.findScoreBatchNoByQuestionId(questionId);
         }
 
         Long finalBatchNo = batchNo;

+ 0 - 1
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/service/MarkingService.java

@@ -129,7 +129,6 @@ public class MarkingService {
         MarkUser maker = markUserRepo.findOne(markTask.getMarkerId());
 
         List<Level> levels = levelRepo.findByWorkId(paper.getWorkId());
-//        Level level = levelRepo.findByWorkIdAndCode(markTask.getWorkId(), levelCode);
         Level level = levels.stream().filter(m->levelCode.equals(m.getCode())).findFirst().get();
 
         markTask.setResult(levelCode);