Как эффективно обрабатывать параллельное создание с помощью Spring Data JPA - PullRequest
0 голосов
/ 27 апреля 2020

Используя Spring Data JPA, у меня есть объект Hibernate с уникальным ограничением на name и context:

@Entity
public class MyEntity {
    @Id
    private String name;
    @Id
    private String context;

// setter, getter, ID class, etc. omitted for brevity
}

, чьи логики создания c выглядят примерно так:

private final MyRepository repository;

@Transactional
public void createOrUpdate(String name, String context) {
  MyEntity entity = repository.findByNameAndContext(name, context)
      .orElseGet(() -> new MyEntity(name, context));

  entity.doSomething();

  repository.save(entity);
}

и где метод репозитория использует блокировку pessimisti c:

public interface MyRepository extends CrudRepository<...> {

  @Lock(PESSIMISTIC_WRITE)
  MyEntity findByNameAndContext(String name, String context); 
}

В большинстве случаев это работает нормально, пока два отдельных потока не попытаются создать одну и ту же сущность одновременно, выполнив оба в orElseGet. По завершении первой транзакции можно будет создать новую строку в базе данных, но вторая не удастся из-за DataIntegrityViolationException.

Я понимаю, почему это не удается, но я не могу найти элегантный способ справиться с этим. Единственное решение, которое я нашел, - это повторить транзакцию при DataIntegrityViolationException.

...