2015-10-18 211 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

是的问题是你正在多线程中做它,而一个线程正在存储更新的计数器值其他线程已保存相同的和这个新的线程是违反约束。你必须对数据库进行行锁定 –