Мне нужно запретить пользователю обновлять сущность, которую другой пользователь уже удалил. Это желаемое поведение:
- Пользователь А просматривает запись @ версия 0.
- Пользователь Б просматривает запись @ версия 0.
- Пользователь A удаляет запись.
- Пользователь Б пытается обновить запись. Но пользователь А уже удален, так что это должно произойти.
Я пытаюсь использовать оптимистичное управление параллелизмом через @Version для достижения этой цели.
У меня есть версионная сущность, такая как:
@Entity
public class Foo {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Version
private Integer version;
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="orderId", nullable=false)
private List<Bar> bars;
Bar
не имеет версии:
@Entity
public class Bar {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
На шаге 3 пользователь A запрашивает удаление. Транзакция создается и вызывается delete
на FooRepository
, который реализует CrudRepository
:
@RestController
public class FooController {
private FooService fooService;
@DeleteMapping
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(Foo foo) {
fooService.delete(foo);
}
@PutMapping
@ResponseStatus(HttpStatus.NO_CONTENT)
public void update(Foo foo) {
fooService.update(foo);
}
@Service
public class FooService {
private FooRepository fooRepo;
@Transactional
public void delete(Foo foo) {
fooRepo.delete(foo);
}
@Transactional
public void update(Foo foo) {
fooRepo.save(foo);
}
На шаге 4 через некоторое время после шага 3 пользователь B вызывает update и
fooRepo.save(foo);
будет вызываться в отдельной транзакции
Это приводит к вставке новой строки foo в базу данных?!? foo
предоставляется клиентом и имеет тот же идентификатор и версию, которые использовались при удалении. Поскольку у foo есть идентификатор, я подумал, что он попытается обновить, а затем поймет, что не может этого сделать, поскольку объект был удален из БД. Вместо этого он игнорирует идентификатор foo и вставляет в БД новую запись с другим идентификатором?!?!?!?
Как я могу получить вместо этого org.springframework.orm.ObjectOptimisticLockingFailureException
?
Рассматривая реализацию save
SimpleJpaRepository
, entityInformation.isNew(entity)
должен возвращать false во время обновления, поскольку идентификатор foo
имеет ненулевое значение. Это означает, что менеджер сущностей должен выполнить слияние.