2014-12-10 24 views
10

Właśnie rozpoczął naukę Hibernate i używam następujący wzór (od documentation) dla każdej transakcji:Hibernate - Czy naprawdę muszę wycofać transakcję, która nie powiodła się tylko do odczytu?

private Session session; 
private Transaction transaction; 

protected List selectAll(Class clazz) throws HibernateException { 
    List objects = null; 
    try { 
     session = MyHibernateHelper.getSessionFactory().openSession(); 
     transaction = session.beginTransaction(); 

     // SELECT ALL 
     objects = session.createCriteria(clazz).list(); 

     transaction.commit(); 
    } catch (HibernateException exc) { 
     if (transaction != null) transaction.rollback(); 
     throw exc; 
    } finally { 
     session.close(); 
    } 
    return objects; 
} 

mogę przyjąć, że każda operacja powinna być opakowane w transakcji. Ale wydaje mi się dziwne i niepotrzebne wycofywanie select, na wypadek niepowodzenia.
Myślę, że mogę bezpiecznie usunąć blok catch z powyższego przykładu. I od dowolnej operacji tylko do odczytu. Czy mam rację?

+5

zależy od sposobu wyboru. jeśli wywołałeś semantykę blokującą, cofnięcie zwolniłoby te blokady. –

Odpowiedz

9

Warto zauważyć, że Hibernate musi współpracować z różnego rodzaju bazami danych dla różnych sytuacji. To, co daje im w swojej dokumentacji, to jak korzystać z Hibernate z dowolnej obsługiwanej bazy danych. I próbują obsługiwać wiele baz danych. Niektóre z tych baz danych mogą obsługiwać nieudane transakcje bez potrzeby jawnego wycofywania, ale Hibernate chce upewnić się, że obejmuje wszystkich.

Weź również pod uwagę, że niepowodzenie transakcji typu "tylko do odczytu" będzie niezwykle rzadkie w życiu. Kiedy to się stanie, nie będzie wiele do zrobienia, ale to, co robi - zwolnienie blokad, jak wskazuje Marc B - nie jest czymś, co chcesz pominąć. Propagujemy więc bardzo małą optymalizację (w oparciu o to, jak rzadko wykonuje się tę ścieżkę), która może mieć złe konsekwencje w pewnych okolicznościach. Posiadanie blokady, która nie zostanie zwolniona, jest tego rodzaju złym skutkiem, który nie objawia się, dopóki inna transakcja nie powiedzie się lub nie zawiedzie, co bardzo utrudnia odnalezienie przyczyny. Blokada nie zostanie zwolniona może spowodować zakleszczenia, więc wpływ na wydajność/dostępność może być fatalny. Byłoby to również trudne do przetestowania, jeśli pojawi się problem, można go było przeoczyć, dopóki nie pojawi się kryzys w środowisku produkcyjnym. W wielu przypadkach jest to coś, czego chcesz uniknąć.

Największy problem polega na tym, że w przypadku każdej transakcji jest dużo kodu standardowego. Moją sugestią jest albo zaimplementowanie pewnych metod narzędziowych za pomocą wywołań zwrotnych lub wzorca poleceń (patrz przykłady Bauera i Kinga Java Persistence z Hibernate dla przykładów), albo przyjąć framework. Istnieje argument przeciwko strukturom, które zaciemniają szczegóły implementacji i utrudniają uczenie się, ale już nauczyłeś się, jak tworzyć te kawałki. Istnieją dojrzałe środowiska, takie jak Seam lub Spring, które obsłużą to za Ciebie.

+0

Położyłeś moje myśli w porządku. Dziękuję Ci! To naprawdę drobna (przedwczesna?) Optymalizacja. W mojej obronie mogę jedynie powiedzieć, że chciałem zminimalizować kod płyty kotła i dojść do prawdy. – naXa

1

Jeśli używasz frameworka lub API, lub czegoś, co naprawdę nie jest pod Twoją kontrolą, zawsze powinieneś szanować ich strategię awaryjną, ponieważ nie wiesz, jak działa wewnętrznie. Być może istnieją inne zasoby do uwolnienia.

+0

'session.close()' wygląda jak metoda czyszczenia. Ale ['transaction.rollback()'] (https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Transaction.html#rollback%28%29) to metoda wymuszania operacji wewnątrz transakcji do przywrócenia. Moim zdaniem może być użyteczny w transakcjach wieloprotokołowych i transakcjach zapisu. Ale nie w nieudanej, atomowej transakcji tylko do odczytu. – naXa

+1

Może to prawda, ale moim zdaniem w większości przypadków jest to zgodne z zaleceniami producenta, nawet jeśli wydaje się to niepotrzebne. – Joachim