2015-10-18 2 views
0

У меня есть объект 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)

Что еще я могу сделать для достижения вышеупомянутого поведения?

ответ

2

Я думаю, что fooRepository.save (foo), наконец, сохраняет те же значения снова и снова в базе данных, поэтому он дает ContrainViolationException. Если вам нужно обновить значение до любого существующего объекта, просто вызовите setCounter, но не вызывайте метод .save(), вместо этого вызывается метод обновления репозитория (если он у вас есть), если он является новым объектом, которого нет в базе данных, а затем вызовите метод save.

Если это делается в спящем режиме, обратитесь по следующей ссылке

Ref: http://www.objectdb.com/java/jpa/persistence/update

+0

:) счастливого кодирование ... –

+0

объект Foo не удался, только fooWithHighestCounter. Я хочу создать новую запись в db с каждым вызовом saveFoo (foo), не обновляя существующий объект. Однако вновь созданный счетчик объекта foo должен быть выше, чем уже существующие значения в базе данных. – Daniel

+1

Да, проблема в том, что вы делаете это в многопоточности, в то время как один поток хранит обновленное значение счетчика, другой поток уже сохранил то же самое, и этот новый поток нарушает ограничение. Вы должны сделать блокировку строк в базе данных. –