简体   繁体   English

与 JPA 同步并发批量更新

[英]Synchronize concurrent batch updates with JPA

This example is modified and simplified, but resembles a real problem I have with legacy code that I am trying to fix.此示例经过修改和简化,但类似于我在尝试修复遗留代码时遇到的真实问题。

I have a MSSQL CAR table (where id is the primary key)我有一个 MSSQL CAR表(其中id是主键)

id ID make制作 status地位
1 1个 BMW宝马 WASHED水洗
2 2个 BMW宝马 DIRTY肮脏的
3 3个 BMW宝马 DIRTY肮脏的
4 4个 Ford福特 DIRTY肮脏的
... ... ... ... ... ...

and a /washNextCars endpoint.和一个/washNextCars端点。

@PatchMapping("/washNextCars")
public ResponseEntity<List<Car>> washNextCars(
      @RequestBody WashCarBody body,
      @RequestParam String status,
      @RequestParam String make,
      @RequestParam Integer limit) {
  ...
}

The following request changes the state of the next 10 cars from DIRTY to WASHED以下请求将接下来的10辆车的 state 从DIRTY更改为WASHED

PATCH /washNextCars?status=DIRTY&make=BMW&limit=10
{
    "status": "WASHED"
}

This is the rough business logic:这是粗略的业务逻辑:

  @Transactional
  public List<Car> washNextCars(WashCarDTO dto) {

    // SELECT TOP ? * FROM CAR WHERE make=? AND status='DIRTY' ORDER BY id ASC 
    List<Car> nextCars = carRepository.findNextCars(limit, make, status);

    // do some complex validation on every car if it can be washed, therefore can't do everything in one single UPDATE query

    cars.forEach(car -> {
      car.setStatus("WASHED");
    });
    carRepository.saveAll(nextCars);
  }

This endpoint works fine when called in sequence, but when called in parallel, it tries to perform the update to the same set of cars at the same time, not the next batch of cars.此端点在顺序调用时工作正常,但在并行调用时,它会尝试同时对同一组汽车执行更新,而不是下一批汽车。

Questions:问题:

  • How can I synchronize the calls until the first one is done?如何在第一个调用完成之前同步调用?
    • Note this has to be achieved on the database level, because the API is deployed as multiple replicas请注意,这必须在数据库级别实现,因为 API 被部署为多个副本
  • I found the following options:我发现了以下选项:
    • @Transactional(isolation = READ_UNCOMMITED)
      • This would require to update the cars to WASHED before any other statement in the business logic is executed, is that correct?这需要在执行业务逻辑中的任何其他语句之前将汽车更新为WASHED ,对吗?
    • @Lock(PESSIMISTIC_WRITE_LOCK) - Did not provide the desired effect @Lock(PESSIMISTIC_WRITE_LOCK) - 没有提供预期的效果
  • What is the right way to achieve this?实现这一目标的正确方法是什么?

Try with UPDLOCK:尝试使用 UPDLOCK:

SELECT ... FROM tab1 WITH (UPDLOCK) WHERE ...

Something similar to类似于

SELECT FOR UPDATE SELECT 更新

in Oracle.在 Oracle。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM