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