2015-10-18 232 views
0

我有一個Foo實體,其字段爲Name,SecondaryNameCounter。 在數據庫中,我對(name,secondaryName,counter)有一個唯一的約束。JPA交易處理

在我有以下方法服務層(其中fooRepositryCrudRepository):

@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放在應用程序上)

我還能做些什麼來實現上述行爲?

回答

2

我認爲fooRepository.save(foo)最後在數據庫中一次又一次地保存相同的值,這就是爲什麼它給ContrainViolationException。如果您需要將值更新到任何現有對象,只需調用setCounter但不要調用.save()方法,而是調用存儲庫的更新方法(如果有),否則如果它是數據庫中尚未存在的新實體,則請致電save方法。

如果在休眠做參考以下鏈接

編號:http://www.objectdb.com/java/jpa/persistence/update

+0

:)快樂編碼... –

+0

foo對象沒有被管理,只是fooWithHighestCounter。我想在每次調用saveFoo(foo)的時候在數據庫中創建一個新記錄,而不是更新現有的實體。但是,新創建的foo對象的計數器應該高於數據庫中已有的值。 – Daniel

+1

是的問題是你正在多線程中做它,而一個線程正在存儲更新的計數器值其他線程已保存相同的和這個新的線程是違反約束。你必須對數據庫進行行鎖定 –