У меня есть объект Foo
с полями Name
, SecondaryName
и Counter
. В БД у меня есть уникальное ограничение на (имя, вторичное имя, счетчик).JPA обработка транзакций
В слое службы у меня есть следующий метод (где fooRepositry
является CrudRepository
):
@Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRES_NEW)
public void saveFoo(Foo foo) {
Optional<TestDto> fooWithHighestCounter= fooRepository.
findTopByNameAndSecondaryNameOrderByCounterDesc(foo.getName(), foo.getSecondaryName());
if (fooWithHighestCounter.isPresent()) {
foo.setCounter(fooWithHighestCounter.get().getCounter() + 1);
} else {
foo.setCounter(1);
}
Foo saved = fooRepository.save(foo);
}
С каждым вызовом на saveFoo
, новая запись должна быть создана в БДЕ с уже существующем высшем счетчиком + 1. Следовательно, должен быть найден самый высокий счетчик, таким образом, @Transactional
.
Тем не менее, я постоянно получаю ContraintViolationException
, когда несколько потоков вызывают метод saveFoo
, так как каждая нить находит такое же самое высокое значение счетчика.
Я предположил, что каждый поток создаст новую транзакцию, и эти транзакции будут выполняться серийно, поэтому никакая транзакция не найдет то же значение счетчика. (Приложение @EnableTransactionManagement
)
Что еще я могу сделать для достижения вышеупомянутого поведения?
:) счастливого кодирование ... –
объект Foo не удался, только fooWithHighestCounter. Я хочу создать новую запись в db с каждым вызовом saveFoo (foo), не обновляя существующий объект. Однако вновь созданный счетчик объекта foo должен быть выше, чем уже существующие значения в базе данных. – Daniel
Да, проблема в том, что вы делаете это в многопоточности, в то время как один поток хранит обновленное значение счетчика, другой поток уже сохранил то же самое, и этот новый поток нарушает ограничение. Вы должны сделать блокировку строк в базе данных. –