Hibernate: różnica między session.get i session.load

88

Z API mogłem zobaczyć, że ma to coś wspólnego z proxy. Ale nie mogłem znaleźć wielu informacji na temat proxy i nie rozumiem różnicy między dzwonieniem session.geta session.load. Czy ktoś mógłby mi wyjaśnić lub skierować do strony referencyjnej?

Dziękuję Ci!!

pomidor
źródło

Odpowiedzi:

117

Z forum Hibernate :

To z książki Hibernate in Action. Dobrze, przeczytaj to ..


Pobieranie obiektów według identyfikatora Poniższy fragment kodu Hibernate pobiera obiekt użytkownika z bazy danych:

User user = (User) session.get(User.class, userID);

Metoda get () jest wyjątkowa, ponieważ identyfikator jednoznacznie identyfikuje pojedyncze wystąpienie klasy. Dlatego często aplikacje używają identyfikatora jako wygodnego uchwytu do trwałego obiektu. Pobieranie według identyfikatora może używać pamięci podręcznej podczas pobierania obiektu, unikając trafienia w bazę danych, jeśli obiekt jest już buforowany. Hibernate udostępnia również metodę load ():

User user = (User) session.load(User.class, userID);

Metoda load () jest starsza; get () zostało dodane do API Hibernate na żądanie użytkownika. Różnica jest banalna:

Jeśli load () nie może znaleźć obiektu w pamięci podręcznej lub bazie danych, zgłaszany jest wyjątek. Metoda load () nigdy nie zwraca wartości null. Metoda get () zwraca wartość null, jeśli nie można znaleźć obiektu.

Metoda load () może zwrócić serwer proxy zamiast rzeczywistej trwałej instancji. Proxy to symbol zastępczy, który uruchamia ładowanie rzeczywistego obiektu przy pierwszym dostępie do niego; Z drugiej strony get () nigdy nie zwraca serwera proxy. Wybór między get () i load () jest łatwy: jeśli masz pewność, że trwały obiekt istnieje, a nieistnienie zostanie uznane za wyjątkowe, load () jest dobrą opcją. Jeśli nie jesteś pewien, czy istnieje trwała instancja o podanym identyfikatorze, użyj funkcji get () i przetestuj zwracaną wartość, aby sprawdzić, czy jest pusta. Użycie metody load () ma dalsze konsekwencje: aplikacja może pobrać poprawne odwołanie (proxy) do trwałej instancji bez uderzania w bazę danych w celu pobrania jej trwałego stanu. Więc load () może nie zgłosić wyjątku, jeśli nie znajdzie trwałego obiektu w pamięci podręcznej lub bazie danych; wyjątek zostanie zgłoszony później, podczas uzyskiwania dostępu do serwera proxy. Oczywiście pobieranie obiektu według identyfikatora nie jest tak elastyczne, jak używanie dowolnych zapytań.

duffymo
źródło
1
Debuguję teraz problem, w którym session.Get <T> () zwraca serwer proxy!
Kent Boogaart
7
Wielkie dzięki! Dla mnie pieniądze brzmiały następująco: „Jeśli load () nie może znaleźć obiektu w pamięci podręcznej lub bazie danych, generowany jest wyjątek. Metoda get () zwraca wartość null, jeśli obiekt nie może zostać znaleziony”.
Chris,
15
JavaDoc for Session.get mówi: Zwróć trwałe wystąpienie danej klasy jednostki z podanym identyfikatorem lub null, jeśli nie ma takiej trwałej instancji. (Jeśli instancja lub serwer proxy dla instancji jest już powiązany z sesją, zwróć tę instancję lub serwer proxy). Zatem sekcja książki, która mówi: „Z drugiej strony get () nigdy nie zwraca proxy”. nie jest poprawne.
Vicky
jeśli korzystasz ze strategii zarządzania transakcjami ze swoimi daos, możesz preferować metodę get (). w przeciwnym razie wywołujący będzie musiał również wykonywać operacje w kontekście otwartej sesji hibernacji na wypadek, gdyby load () zwrócił proxy. na przykład, jeśli wykonujesz MVC, kontroler może wykonać dao.load (), a następnie zgłosić wyjątek podczas późniejszej próby uzyskania dostępu do obiektu proxy, jeśli nie ma prawidłowej sesji. wykonanie dao.get () zwróci rzeczywisty obiekt do kontrolera niezależnie od sesji (zakładając, że istnieje)
dev
Problem, który opisał @Vicky, może powodować bóle głowy i nie widzę w tym żadnej korzyści. W niektórych przypadkach dodatkowo potrzebuję identyfikatora do dalszych sparametryzowanych zapytań. Ale ponieważ proxy obiektu jest już w sesji, funkcja pobierająca identyfikator zwraca wartość null. Dlaczego pobierają proxy zamiast rzeczywistej instancji, jeśli ten serwer proxy jest w sesji?
djmj
15

Cóż, przynajmniej w nhibernate, session.Get (id) załaduje obiekt z bazy danych, podczas gdy session.Load (id) tylko utworzy do niego obiekt proxy bez opuszczania serwera. Działa tak jak każda inna leniwie ładowana właściwość w Twoich POCO (lub POJO :). Następnie możesz użyć tego serwera proxy jako odniesienia do samego obiektu w celu utworzenia relacji itp.

Pomyśl o tym jak o przedmiocie, który zachowuje tylko identyfikator, a resztę załaduje, jeśli kiedykolwiek będziesz go potrzebować. Jeśli po prostu przekazujesz to sobie, aby tworzyć relacje (jak FK), identyfikator jest wszystkim, czego kiedykolwiek będziesz potrzebować.

Jorge Alves
źródło
więc chcesz powiedzieć, że load (id) najpierw uderzy w bazę danych, aby sprawdzić, czy jest to prawidłowy identyfikator, czy nie, a następnie zwróci obiekt proxy, a kiedy uzyskasz dostęp do właściwości tego obiektu, ponownie trafi do bazy danych? czy to nie jest nieprawdopodobny scenariusz? dwa zapytania do załadowania pojedynczego obiektu?
faisalbhagat
Nie, funkcja load (id) w ogóle nie zweryfikuje identyfikatora, więc nie ma połączeń w obie strony do bazy danych. Używaj go tylko wtedy, gdy masz pewność, że jest ważny.
Jorge Alves,
9

session.load () zawsze zwróci „proxy” (termin hibernacji) bez uderzania w bazę danych. W Hibernate proxy to obiekt o podanej wartości identyfikatora, jego właściwości nie zostały jeszcze zainicjalizowane, po prostu wygląda jak tymczasowy fałszywy obiekt. Jeśli nie zostanie znaleziony żaden wiersz, zgłosi ObjectNotFoundException.

session.get () zawsze trafia do bazy danych i zwraca rzeczywisty obiekt, obiekt reprezentujący wiersz bazy danych, a nie proxy. Jeśli nie znaleziono wiersza, zwraca wartość null.

Wydajność z tymi metodami również powoduje różnice. pomiedzy dwa...

Vishal Sharma
źródło
3

Jeszcze jeden dodatkowy punkt:

metoda get klasy Hibernate Session zwraca wartość null, jeśli obiekt nie zostanie znaleziony ani w pamięci podręcznej, ani w bazie danych. while load () zgłasza wyjątek ObjectNotFoundException, jeśli obiekt nie zostanie znaleziony w pamięci podręcznej ani w bazie danych, ale nigdy nie zwróci wartości null.

madhu_karnati
źródło
2

Jedną pośrednią konsekwencją użycia „load” zamiast „get” jest to, że optymistyczne blokowanie przy użyciu atrybutu wersji może nie działać zgodnie z oczekiwaniami. Jeśli ładowanie po prostu tworzy proxy i nie czyta z bazy danych, właściwość version nie jest ładowana. Wersja zostanie załadowana tylko wtedy, gdy / jeśli później odwołasz się do właściwości obiektu, wyzwalając wybór. W międzyczasie inna sesja może zaktualizować obiekt, a Twoja sesja nie będzie miała oryginalnej wersji, której potrzebuje do optymistycznego sprawdzenia blokady - więc aktualizacja sesji nadpisze aktualizację innej sesji bez ostrzeżenia.

Oto próba naszkicowania tego scenariusza z dwiema sesjami pracującymi z obiektem o tym samym identyfikatorze. Początkowa wersja obiektu w DB to 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

Właściwie chcemy, aby zatwierdzenie sesji 1 zakończyło się niepowodzeniem z optymistycznym wyjątkiem blokady, ale tutaj się powiedzie.

Użycie polecenia „get” zamiast „load” umożliwia obejście problemu, ponieważ get natychmiast wyda polecenie select, a numery wersji zostaną załadowane w odpowiednim czasie dla optymistycznego sprawdzenia blokad.

SteveT
źródło
0

Musimy też zachować ostrożność podczas korzystania z load, ponieważ zgłosi wyjątek, jeśli obiekt nie jest obecny. Musimy go używać tylko wtedy, gdy mamy pewność, że obiekt istnieje.

Sanjay
źródło
0

Doskonałe wyjaśnienie można znaleźć pod adresem http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
Zawsze zwraca „proxy” (termin hibernacji) bez trafienie do bazy danych.
W Hibernate proxy to obiekt o podanej wartości identyfikatora, jego właściwości nie zostały jeszcze zainicjalizowane, po prostu wygląda jak tymczasowy fałszywy obiekt.
Zawsze zwróci obiekt proxy z podaną wartością tożsamości, nawet jeśli wartość tożsamości nie istnieje w bazie danych. Jednak podczas próby zainicjowania serwera proxy przez pobranie jego właściwości z bazy danych trafi on do bazy danych za pomocą instrukcji select. Jeśli nie zostanie znaleziony żaden wiersz, zostanie zgłoszony wyjątek ObjectNotFoundException.
session.get ():
Zawsze trafia do bazy danych (jeśli nie znajduje się w pamięci podręcznej) i zwraca rzeczywisty obiekt, obiekt, który reprezentuje wiersz bazy danych, a nie serwer proxy.
Jeśli nie znaleziono wiersza, zwraca wartość null.

czarny jack
źródło
0

load () nie może znaleźć obiektu w pamięci podręcznej lub bazie danych, generowany jest wyjątek, a metoda load () nigdy nie zwraca wartości null.

Metoda get () zwraca wartość null, jeśli nie można znaleźć obiektu. Metoda load () może zwracać proxy zamiast prawdziwej trwałej instancji get () nigdy nie zwraca proxy.

Yasser Shaikh
źródło