Załóżmy, że mam dwa różne wątki, T1 i T2, dostęp do jednocześnie tej samej bazy danych i pobieranie danych z tej samej tabeli.Jak uniknąć dwóch różnych wątków przeczytać te same wiersze z DB (Hibernate i Oracle 10g)
Teraz przy uruchamianiu wątku muszę pobrać dane z tabeli i zapisać wiersze w kolekcji, którą następnie wykorzystam do wykonania pracy w innym miejscu. Nie chcę, aby te dwa wątki mogły przetwarzać te same dane, ponieważ spowoduje to powielenie (i długą) pracę. Aby być bardziej konkretnym, jest to aplikacja dla przedsiębiorstw, która musi załadować niektóre rekordy podczas uruchamiania i przechowywać ją w kolekcji, aby wykonać dodatkową pracę. Problem polega na tym, że w środowisku klastrowym może to spowodować, że dwa różne wystąpienia załadują te same dane, a zatem praca może zostać powielona. Dlatego chcę, aby wiersze były ładowane tylko raz przez pojedynczą instancję.
Jak mogę uniknąć tego scenariusza?
Używam obecnie Hibernacji i Oracle 10g. Oto moje dotychczasowe rozwiązania:
Programowo zablokuj wiersz. Pierwszy, który go czyta, ustawia pewną "zamkniętą" kolumnę na wartość prawda, ale zakleszczenie najprawdopodobniej nastąpi, jeśli pierwszy wątek umrze bez ustawiania wiersza jako "przetworzony".
Korzystanie z pesymistycznego blokowania. Próbowałem z LockMode.UPGRADE, ale to nie wydaje się pomóc, ponieważ wciąż jestem w stanie odczytać dane z obu wątków w tym samym czasie.
public List<MyObject> getAllNtfFromDb() { Session session = HibernateUtil.getOraclesessionfactory().openSession(); Query q = session.createQuery( "from MyObject n where n.state = 'NEW'"); List<MyObject> list = (List<MyObject>) q.list(); for (int i=0; i<list.size(); i++) session.lock(list.get(i), LockMode.UPGRADE); return list; }
Wszelkie inne wskazówki? Co ja robię źle?
Dzięki.
Może możesz użyć instrukcji select for update? – soilworker