JPA, a zablokowanie encji na czas zapisu

0

Witam,
Mam problem w jaki sposób najlepiej zapobiegaać race-conditions w JPA. To powinno być dość proste.

@Statless
public class SimpleDao implements ISimpleDao {

    @PersistenceContext
    private EntityManager em;

    @Override
    public void save(SimpleEntity m) {
        if (countIllegal(m) == 0) {
            em.persist(m);
        }
    }
     
    // metoda countSimilar wyszukuje rekordy, które zabraniają dodaniu

    @Override
    public long countIllegal(SimpleEntity m) {
        Query q = em.createNamedQuery("SimpleEntity.countIllegal");
        q.setParameter("date", m.getName());
        return (long) q.getSingleResult();
    }


}

Named query to prosta agregacja typu SELECT COUNT(encja), ktora zawsze zwroci singleResult.

Czy ta metoda jest bezpieczna? Wydaje mi się, że powinienem założyć lock na query JPQL jak FOR UPDATE w SQL. Jak to zrobic?

Pozdrawiam

0

Nie rozumiem twojego pytania ani tego czym dla ciebie jest "race condition" w JPA. Rozumiesz chyba że SZBD ma zaimplementowane metody izolacji trasakcji i generalnie twoim zadaniem jest ustawić taki poziom izolacji jaki cię interesuje i tyle?

0

Przeczytalem ten tekst.

Czy tak bedzie ok?

@NamedQueries({
    @NamedQuery(name = "SimpleEntity.countSimilar", query = "SELECT COUNT(w) FROM SimpleEntity w WHERE w.nazwa = :nazwa", lockMode = LockModeType.PESSIMISTIC_WRITE)
}))
})
0

Tak, ale pozomy izolacji transakcji sa generalnie zawodne.

Piszac 'race condition' mialem na mysli, wejda jednoczesnie w tym samym momencie dwie rozne transakcje i zobacza, ze jest 0. I dodadza. Jedna z tych dwoch transakcji nie powinna sie wykonac. Powinna byc blokada. W SQL robilem to za pomoca FOR UPDATE. Inaczej zdarzaly sie np. deadlocki.

0

Jedna, później zacommitowana, z transakcji się nie wykona ponieważ "odpadnie" na weryfikacji po stronie bazy danych. Co prawda całość wybuchnie, ale to nie jest problem. Co rozumiesz przez " pozomy izolacji transakcji sa generalnie zawodne.".

0

@koziolek:
Mialem na mysli np. fantomy czy niepowtarzalne odczyty piszac o zawodnosci transakcji.

Jeśli możesz wyjaśnij dlaczego odpoadnie 'na weryfikacji po stronie bazy danych'.

Jestem pewien, że na pewno odpadłaby, gdybym założył unikalny indeks na kolumnie 'nazwa'. W innym przypadku nie jestem pewien dlaczego tak mialoby sie stac.

0

Jeżeli zaczynasz transakcję to po stronie bazy jest przypisywany do niej numer wersji danych na których transakcja zamierza pracować (unikalny, niepowtarzalny i uszeregowany) jeżeli transakcja w czasie commitu zobaczy, że dane mają inne numery wersji to się zrollbackuje.

0

Dzięki!

0

@Mlody93 o_O jak sobie źle ustawisz poziom izolacji to się potem nie dziw że masz problemy.
@Koziołek ja mam wrażenie że on chce opierać logikę aplikcji o sprawdzenie stanu obiektów w bazie. Problemem nie jest transakcja tylko to, że on chce sie bawić w compare and swap w oparciu o obiekty w bazie. Co generalnie uważam za średni pomysł. Skoro to jest logika biznesowa aplikacji to aplikacja powinna ten stan wewnętrznie przechowywać a nie kombinować z blokowaniem rekordów w bazie.

0

Probowalem przeniesc myslenie wyniesione z pisania procedur skladowanych do EJB. Tam trzeba bylo robic np. FOR UPDATE, aby transakcje nie zakleszczaly sie jesli kilkanascie transakcji probowaly wykonac modyfikacje rekordu w bazie, a nie bylo blokowania. Generalnie sama procedura skladowana stanowila transakcje: dopiero jednak FOR UPDATE powodowal, ze nie dochodzilo do zakleszczen (exclusive lock).

@Shalom: w praktyce nikt nie uzywa poziomu Serializable, na ktorym fantomy nie wystepuja. Domyslny poziom to reapetable reads. I nie jest odporny na fantomy. Taki kompromis. Na brudne odczyty juz tak.

Problem w tym, ze nie zawsze mozesz przechowywac stan obiektow w bazie. Poniewaz obiektow w bazie moze byc bardzo duzo.

0

Brudne rozwiazanie to po prostu unikalny indeks. Moim zdaniem ono spowoduje rollback transakcji z powodu bledu JDBC.

1 użytkowników online, w tym zalogowanych: 0, gości: 1