我有一個Foo
實體,其字段爲Name
,SecondaryName
和Counter
。 在數據庫中,我對(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
每次調用,一個新的記錄應在數據庫中創建與已經存在的最高計數器+因此,必須找到最高的櫃檯,因此@Transactional
。
但是,當多個線程調用saveFoo
方法時,我總是得到ContraintViolationException
,因爲每個線程都找到相同的最高計數器值。
我認爲每個線程都會創建一個新的事務,並且這些事務將連續運行,因此沒有事務會找到相同的計數器值。 (將@EnableTransactionManagement
放在應用程序上)
我還能做些什麼來實現上述行爲?
:)快樂編碼... –
foo對象沒有被管理,只是fooWithHighestCounter。我想在每次調用saveFoo(foo)的時候在數據庫中創建一個新記錄,而不是更新現有的實體。但是,新創建的foo對象的計數器應該高於數據庫中已有的值。 – Daniel
是的問題是你正在多線程中做它,而一個線程正在存儲更新的計數器值其他線程已保存相同的和這個新的線程是違反約束。你必須對數據庫進行行鎖定 –