Java 为什么';Spring JPA是否可以进行同步?
我试着做这么简单的事情——只是原子地调用两个数据库调用 我在数据库中有一个队列(表)。一列为“已加载”。我有一个SpringMVC(带SpringBoot)应用程序,它使用SpringJPA和Hibernate 我的控制器: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
@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);
}
}
在我的代码中,您可以看到我使用了所有东西来同步从队列读取和更新:
我不明白我做错了什么。只是想一下,在这里使用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);
}