2010-02-25 12 views
9

A ma jednostkę JPA, która ma znacznik czasu i wyróżnia się złożonym polem identyfikatora. Potrzebuję zaktualizować znacznik czasu w jednostce, która już została zapisana, w przeciwnym razie utworzyć i zapisać nowy obiekt z bieżącym znacznikiem czasu.Utwórz nowy lub zaktualizuj istniejący podmiot za jednym razem, korzystając z wersji JPA

Jak się okazuje, zadanie nie jest tak proste, jak się wydaje od pierwszego wejrzenia. Problem polega na tym, że w środowisku współbieżnym pojawia się nieprzyjemny wyjątek "Unikatowy indeks lub naruszenie klucza głównego". Oto mój kod:

// Load existing entity, if any. 
Entity e = entityManager.find(Entity.class, id); 
if (e == null) { 
    // Could not find entity with the specified id in the database, so create new one. 
    e = entityManager.merge(new Entity(id)); 
} 
// Set current time... 
e.setTimestamp(new Date()); 
// ...and finally save entity. 
entityManager.flush(); 

Należy zauważyć, że w tym przykładzie identyfikator jednostki nie jest generowany na insert, jest znany z góry.

Gdy dwa lub więcej wątków uruchomić ten blok kodu równolegle, mogą jednocześnie uzyskać null z entityManager.find(Entity.class, id) wywołanie metody, więc starają się zaoszczędzić dwa lub więcej podmiotów, w tym samym czasie, z tym samym identyfikatorem wyniku błędu .

Myślę, że istnieje niewiele rozwiązań tego problemu.

  1. Oczywiście mogę zsynchronizować ten blok kodu z globalną blokadą, aby zapobiec równoczesnemu dostępowi do bazy danych, ale czy byłby to najbardziej wydajny sposób?
  2. Niektóre bazy danych obsługują bardzo przydatne instrukcje MERGE, które aktualizują istniejący lub tworzą nowy wiersz, jeśli żaden nie istnieje. Ale wątpię, że OpenJPA (moja implementacja JPA) obsługuje to.
  3. Zdarzenie, jeśli JPA nie obsługuje SQL MERGE, zawsze mogę wrócić do zwykłego starego JDBC i zrobić, co chcę z bazą danych. Ale nie chcę zostawiać wygodnego API i bałaganu z włochatą kombinacją JDBC + SQL.
  4. Istnieje magiczna sztuczka, aby naprawić go za pomocą standardowego interfejsu API JPA, ale jeszcze go nie znam.

Proszę o pomoc.

Odpowiedz

1

Masz na myśli izolację transakcji transakcji JPA. To znaczy. jakie jest zachowanie transakcji, gdy uzyskują dostęp do zasobów innych transakcji.

Według this article:

READ_COMMITTED jest oczekiwany poziom izolacji transakcji dla domyślnej za pomocą [..] EJB3 WZP

Oznacza to, że - tak, masz problemy z powyższym kodem .

Ale JPA nie obsługuje niestandardowych poziomów izolacji.

This thread omawia ten temat szerzej. W zależności od tego, czy używasz Springa czy EJB, myślę, że możesz skorzystać z właściwej strategii transakcji.

+0

Oba odnośniki są zepsute – Sergey

Powiązane problemy