我试图了解我是否在做正确的交易。我在 Spring Boot 上使用 PostgreSQL 构建了一个小型 REST API。案例是“保留” - 传入请求应该找到某个实体并将其状态设置为“保留”。必须防止的是两个请求返回同一个实体。目前我将整个端点处理程序包装在一个事务中(如下)。据我了解,系统基本上会对当前状态进行快照,然后第一个请求将修改表。问题是,当第二个请求进来时,在第一个仍然在事务内时,会发生什么?我需要 find() 查询将等到第一个事务结束然后继续。至少在理论上,它会像这样工作吗?@Transactional@RequestMapping(value = "/newTour", method = RequestMethod.GET, headers = "Accept=application/xml", consumes = "application/xml", produces = "application/xml")public @ResponseBody ResponseEntity<?> addTourReservation(@RequestBody PartialTourUpdate partialUpdate) { try{ List<Tour> tours = tourRepo.findFirstPessimisticByTourTypeInAndStatusOrderByPriorityDesc(partialUpdate.getTourType(), Tour.STATUS_OPEN); if (tours != null && tours.size() > 0) { Tour tour = tours.get(0); tour.setReservationID(partialUpdate.getReservationID()); tour.setStatus(Tour.STATUS_TO_RESERVE); tourRepo.save(tour); orderRepo.updateReservationStatus(true, tour.getTourID()); return new ResponseEntity<Tour>(tour, HttpStatus.CREATED); } else { rM.setValue(ResultMessage.ErrorCode.LOS_NOT_FOUND); rM.log(); return new ResponseEntity<ResultMessage>(rM, HttpStatus.OK); } } catch (Exception e) { rM.setValue(ResultMessage.ErrorCode.LOS_UNKNOWN); rM.log(); return new ResponseEntity<ResultMessage>(rM, HttpStatus.OK); }
2 回答
月关宝盒
TA贡献1772条经验 获得超5个赞
锁定一行以防止并发事务读取它意味着排他锁。
使用 JPA,这是使用PESSIMISTIC_WRITE锁实现的
您需要使用
@Lock(LockModeType.PESSIMISTIC_WRITE)
请注意,这将跨越整个tour
表的锁,防止任何并发事务读取任何行,这可能意味着重负载下的线程争用问题。
另一种方法是选择所有可用的游览,并在列表中保留一个随机选择的游览,如果更新触发异常,则使用entityManager.lock(tour, LockModeType.PESSIMISTIC_FORCE_INCREMENT)
(实体必须具有@Version
属性)预先锁定它(并且仅锁定它,而不是整个表)(如果另一笔交易已经保留了它)只需选择另一个并尝试更新它。
但是,最好的方法仍然是让数据库处理并发问题并使用单个 SQL(或 HQL)更新查询保留“游览”(您的方法中没有业务逻辑,因此您无需检索和操作更新之前的实体)。
添加回答
举报
0/150
提交
取消