Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么';Spring JPA是否可以进行同步?_Java_Spring_Multithreading_Synchronization_Spring Orm - Fatal编程技术网

Java 为什么';Spring JPA是否可以进行同步?

Java 为什么';Spring JPA是否可以进行同步?,java,spring,multithreading,synchronization,spring-orm,Java,Spring,Multithreading,Synchronization,Spring Orm,我试着做这么简单的事情——只是原子地调用两个数据库调用 我在数据库中有一个队列(表)。一列为“已加载”。我有一个SpringMVC(带SpringBoot)应用程序,它使用SpringJPA和Hibernate 我的控制器: @RequestMapping(value = "/queue/next", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @Timed

我试着做这么简单的事情——只是原子地调用两个数据库调用

我在数据库中有一个队列(表)。一列为“已加载”。我有一个SpringMVC(带SpringBoot)应用程序,它使用SpringJPA和Hibernate

我的控制器:

@RequestMapping(value = "/queue/next",
    method = RequestMethod.GET,
    produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public ResponseEntity<List<String>> getNext() {
    List<String> pair = queueService.getNext();

    if (pair != null) {
        log.warn("!!! SQL !!! Next {} -> {}", pair.get(0), pair.get(1));
        return new ResponseEntity<>(
            pair,
            HttpStatus.OK
        );
    } else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}
在我的代码中,您可以看到我使用了所有东西来同步从队列读取和更新:

  • 我用过ReentrantLock
  • 我在服务的方法上使用了synchronized
  • 我已清除关联实体管理器
  • 但我可以从日志中看到,当100多个用户开始快速调用该方法时,该方法正在从队列中返回重复的项


    我不明白我做错了什么。只是想一下,在这里使用JPA时的问题。

    原子性和隔离性是由数据库事务提供的,而不是由JVM锁提供的。在典型的默认READ_COMMITTED隔离级别中,数据库事务不会看到其他事务尚未提交的任何更改。此外,您似乎认为save()会将队列写入数据库。没有。save()在这里完全没有用处。更新由JPA在刷新时完成(这里最有可能是在提交事务之前)。您需要从数据库事务和乐观或悲观的数据库锁的角度重新考虑您的逻辑。@jbnize如果我的服务类标记为
    @Transactional
    ,那么该方法
    UpdateQueueService.findNextAvailable()
    将在一个事务中实现所有功能,这是对的。我需要通过
    @Lock(LockModeType.epositic_WRITE)
    标记我的存储库方法
    updatequeurepository.findNextAvailable()
    private static final ReentrantLock lock = new ReentrantLock(true);
    
    public List<String> getNext() {
        QueueDTO queue;
    
        log.warn("!!! SQL !!! {}", System.identityHashCode(lock));
    
        lock.lock();
        try {
            queue = updateQueueService.findNextAvailable();
            if (queue == null) return null;
        } finally {
            lock.unlock();
        }
    
        List<String> result = new ArrayList<>(2);
        result.add(queue.getStationFromName());
        result.add(queue.getStationToName());
        return result;
    }
    
    public synchronized QueueDTO findNextAvailable() {
        entityManager.clear();
    
        Queue queue = updateQueueRepository.findNextAvailable();
    
        if (queue == null) return null;
    
        queue.setLoaded(true);
        updateQueueRepository.save(queue);
    
        return updateQueueMapper.updateQueueToUpdateQueueDTO(queue);
    }