Oto moje rozumienie metod. Głównie są one oparte na interfejsie API, ponieważ nie używam ich wszystkich w praktyce.
saveOrUpdate
Połączenia zapisują lub aktualizują w zależności od niektórych kontroli. Np. Jeśli nie ma identyfikatora, wywoływane jest save. W przeciwnym razie wywoływana jest aktualizacja.
zapisz
Utrzymuje byt. Przydzieli identyfikator, jeśli nie istnieje. Jeśli tak, to zasadniczo robi aktualizację. Zwraca wygenerowany identyfikator encji.
aktualizacja
Próby utrwalenia jednostki przy użyciu istniejącego identyfikatora. Jeśli nie istnieje żaden identyfikator, uważam, że zgłoszony został wyjątek.
saveOrUpdateCopy
To jest przestarzałe i nie powinno być dłużej używane. Zamiast tego jest ...
scalić
Teraz moja wiedza zaczyna słabnąć. Ważną rzeczą jest tutaj różnica między istotami przejściowymi, odłączonymi i trwałymi. Aby uzyskać więcej informacji o stanach obiektów, spójrz tutaj . Dzięki funkcji Zapisz i aktualizuj masz do czynienia z obiektami trwałymi. Są powiązane z sesją, więc Hibernacja wie, co się zmieniło. Ale kiedy masz obiekt przejściowy, nie ma w tym żadnej sesji. W takich przypadkach należy użyć scalania do aktualizacji i utrwalania do zapisywania.
utrzymują
Jak wspomniano powyżej, jest stosowany na przemijających przedmiotów. Nie zwraca wygenerowanego identyfikatora.
źródło
update
obiekt przejściowy jest w porządku, nie dostałem wyjątku.Zobacz forum Hibernacji, aby uzyskać wyjaśnienie subtelnych różnic między utrzymywaniem a zapisywaniem. Wygląda na to, że różnica polega na tym, kiedy instrukcja INSERT jest ostatecznie wykonywana. Ponieważ funkcja save zwraca identyfikator, instrukcja INSERT musi zostać wykonana natychmiast, niezależnie od stanu transakcji (co na ogół jest złą rzeczą). Persist nie wykona żadnych instrukcji poza bieżącą transakcją tylko w celu przypisania identyfikatora. Save / Persist oba działają na instancjach przejściowych , tj. Instancjach, które nie mają jeszcze przypisanego identyfikatora i jako takie nie są zapisywane w bazie danych.
Zaktualizuj i scal oba działają na odłączonych instancjach , tj. Instancjach, które mają odpowiedni wpis w bazie danych, ale które nie są obecnie dołączone do sesji ani nie są przez nią zarządzane. Różnica między nimi polega na tym, co dzieje się z instancją przekazywaną do funkcji. aktualizacja próbuje ponownie dołączyć instancję, co oznacza, że nie może być teraz żadnej innej instancji trwałej jednostki dołączonej do sesji, w przeciwnym razie zostanie zgłoszony wyjątek. Scalanie , jednak wystarczy skopiować wszystkie wartości do trwałej instancji w sesji (która zostanie załadowana, jeśli nie jest aktualnie ładowana). Obiekt wejściowy nie ulega zmianie. Więc scal jest bardziej ogólne niż aktualizacja , ale może zużywać więcej zasobów.
źródło
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.
Czy możesz mi powiedzieć, w jaki sposób wkładka może się zdarzyć poza sesją i dlaczego jest tak źle?INSERT
. W związku z tym w takich przypadkach nie można teraz zwrócić identyfikatora bez wygenerowania go i aby go wygenerować, należy uruchomićINSERT
teraz . Ponieważ transakcja długo działa nie jest prowadzony w tej chwili , ale tylko na zobowiązać, że jedynym sposobem, aby wykonaćINSERT
teraz, aby go uruchomić poza TX.Ten link wyjaśnia w dobry sposób:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
Wszyscy mamy problemy, z którymi spotykamy się tak rzadko, że kiedy je ponownie widzimy, wiemy, że je rozwiązaliśmy, ale nie pamiętamy, jak to zrobić.
Wyjątek NonUniqueObjectException zgłaszany podczas używania Session.saveOrUpdate () w Hibernacji jest jednym z moich. Dodam nową funkcjonalność do złożonej aplikacji. Wszystkie moje testy jednostkowe działają dobrze. Następnie, testując interfejs użytkownika, próbując zapisać obiekt, zaczynam otrzymywać wyjątek z komunikatem „inny obiekt o tej samej wartości identyfikatora był już powiązany z sesją”. Oto przykładowy kod z Java Persistence with Hibernate.
Aby zrozumieć przyczynę tego wyjątku, ważne jest zrozumienie odłączonych obiektów i tego, co dzieje się po wywołaniu metody saveOrUpdate () (lub po prostu update ()) na odłączonym obiekcie.
Kiedy zamykamy pojedynczą sesję hibernacji, trwałe obiekty, z którymi pracujemy, są odłączane. Oznacza to, że dane są nadal w pamięci aplikacji, ale Hibernacja nie jest już odpowiedzialna za śledzenie zmian w obiektach.
Jeśli następnie zmodyfikujemy nasz odłączony obiekt i chcemy go zaktualizować, musimy ponownie dołączyć obiekt. Podczas tego procesu ponownego dołączania Hibernacja sprawdzi, czy istnieją inne kopie tego samego obiektu. Jeśli znajdzie jakiś, musi nam powiedzieć, że nie wie już, czym jest „prawdziwa” kopia. Być może wprowadzono inne zmiany w tych innych kopiach, które, jak się spodziewamy, zostaną zapisane, ale Hibernate nie wie o nich, ponieważ wtedy nie zarządzał nimi.
Zamiast zapisywać potencjalnie złe dane, Hibernacja informuje nas o problemie za pośrednictwem wyjątku NonUniqueObjectException.
Co więc mamy zrobić? W Hibernacji 3 mamy merge () (w Hibernacji 2 użyj saveOrUpdateCopy ()). Ta metoda zmusi Hibernację do skopiowania wszelkich zmian z innych odłączonych instancji do instancji, którą chcesz zapisać, a tym samym scali wszystkie zmiany w pamięci przed zapisaniem.
Należy zauważyć, że funkcja scalania zwraca odwołanie do nowo zaktualizowanej wersji instancji. To nie jest ponowne podłączanie przedmiotu do sesji. Jeśli przetestujesz na przykład równość (item == item3), przekonasz się, że w tym przypadku zwraca false. Prawdopodobnie będziesz chciał pracować z item3 od tego momentu.
Należy również zauważyć, że interfejs API Java Persistence (JPA) nie ma pojęcia odłączonych i ponownie podłączonych obiektów, i korzysta z EntityManager.persist () i EntityManager.merge ().
Ogólnie stwierdziłem, że przy użyciu Hibernacji metoda saveOrUpdate () jest zwykle wystarczająca dla moich potrzeb. Zwykle muszę używać scalania tylko wtedy, gdy mam obiekty, które mogą mieć odwołania do obiektów tego samego typu. Ostatnio przyczyną wyjątku był kod potwierdzający, że odwołanie nie było rekurencyjne. W ramach sprawdzania poprawności ładowałem ten sam obiekt do mojej sesji, powodując błąd.
Gdzie napotkałeś ten problem? Czy scalenie działało dla Ciebie, czy potrzebujesz innego rozwiązania? Czy wolisz zawsze używać scalania, czy wolisz używać go tylko w razie potrzeby w określonych przypadkach
źródło
W rzeczywistości różnica między hibernacją
save()
apersist()
metodami zależy od używanej klasy generatora.Jeśli nasza klasa generatora jest przypisana, nie ma różnicy między
save()
ipersist(
) metodami. Ponieważ generator „przypisany” oznacza, że jako programista musimy podać wartość klucza podstawowego, aby zapisać ją w bazie danych [Mam nadzieję, że znasz tę koncepcję generatorów] W przypadku innej niż przypisana klasa generatora, załóżmy, że nasza nazwa klasy generatora to Przyrost hibernuj to samo przypisze wartość identyfikatora klucza podstawowego do bazy danych w prawo [inny niż przypisany generator, hibernacja służy tylko do zapamiętania wartości identyfikatora klucza podstawowego zapamiętaj], więc w tym przypadku, jeśli wywołamysave()
lubpersist()
metodę, to wstawi rekord do baza danych normalnie Ale słyszę, żesave()
metoda może zwrócić tę wartość identyfikatora klucza podstawowego, która jest generowana przez hibernację i możemy to zobaczyć przezW tym samym przypadku
persist()
klient nigdy nie zwróci żadnej wartości.źródło
Znalazłem dobry przykład pokazujący różnice między wszystkimi metodami hibernacji:
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example
W skrócie, zgodnie z powyższym linkiem:
zapisać()
trwać()
saveOrUpdate ()
Może być używany z transakcją lub bez, i podobnie jak save (), jeśli jest używany bez transakcji, zmapowane jednostki nie zostaną zapisane, chyba że opróżnimy sesję.
Wyniki wstawiania lub aktualizowania zapytań na podstawie dostarczonych danych. Jeśli dane są obecne w bazie danych, wykonywane jest zapytanie o aktualizację.
aktualizacja()
łączyć()
Również dla praktycznych przykładów ich wszystkich, proszę odwołać się do linku, o którym wspomniałem powyżej, zawiera przykłady wszystkich tych różnych metod.
źródło
Jak wyjaśniłem w tym artykule , powinieneś preferować metody JPA przez większość czasu i
update
zadania przetwarzania wsadowego.WZP lub Hibernacja może znajdować się w jednym z następujących czterech stanów:
Przejście z jednego stanu do drugiego odbywa się za pomocą metod EntityManager lub Session.
Na przykład WZP
EntityManager
zapewnia następujące metody zmiany stanu encji.Hibernacji
Session
realizuje wszystkie JPAEntityManager
metody i zawiera kilka dodatkowych metod, takich jak zmiana stanu podmiotusave
,saveOrUpdate
iupdate
.Trwać
Aby zmienić stan bytu z Przejściowy (Nowy) na Zarządzany (Utrwalony), możemy użyć
persist
metody oferowanej przez JPA,EntityManager
która jest również dziedziczona przez HibernacjęSession
.Dlatego podczas wykonywania następującego przypadku testowego:
Hibernacja generuje następujące instrukcje SQL:
Zauważ, że
id
przypisuje się to przed dołączeniemBook
bytu do bieżącego kontekstu trwałości. Jest to konieczne, ponieważ jednostki zarządzane są przechowywane wMap
strukturze, w której klucz jest tworzony przez typ jednostki i jej identyfikator, a wartością jest odwołanie do jednostki. To jest powód, dla którego JPAEntityManager
i HibernacjaSession
są znane jako pamięć podręczna pierwszego poziomu.Podczas połączenia
persist
jednostka jest dołączona tylko do aktualnie działającego kontekstu trwałości, a WSTAW można odłożyć do momentuflush
zostanie wywołane.Jedynym wyjątkiem jest generator TOŻSAMOŚCI, który natychmiast uruchamia WSTAW, ponieważ jest to jedyny sposób, w jaki może uzyskać identyfikator jednostki. Z tego powodu Hibernacja nie może wsadowo wstawiać wstawek dla encji korzystających z generatora TOŻSAMOŚCI. Więcej informacji na ten temat można znaleźć w tym artykule .
Zapisać
save
Metoda specyficzna dla Hibernacji poprzedza JPA i jest dostępna od początku projektu Hibernacja.Aby zobaczyć, jak
save
działa metoda, rozważ następujący przypadek testowy:Po uruchomieniu powyższego przypadku testowego Hibernacja generuje następujące instrukcje SQL:
Jak widać, wynik jest identyczny z
persist
wywołaniem metody. Jednak w przeciwieństwiepersist
dosave
metody zwraca identyfikator jednostki.Aby uzyskać więcej informacji, sprawdź ten artykuł .
Aktualizacja
update
Metoda specyficzna dla hibernacji ma na celu ominięcie mechanizmu sprawdzania brudności i wymuszenie aktualizacji encji w czasie opróżniania.Aby zobaczyć, jak
update
działa metoda, rozważ następujący przykład, który utrzymujeBook
jednostkę w jednej transakcji, a następnie modyfikuje ją, gdy jednostka jest w stanie odłączonym, i wymusza aktualizację SQL za pomocąupdate
wywołania metody.Podczas wykonywania powyższego przypadku testowego Hibernacja generuje następujące instrukcje SQL:
Zauważ, że
UPDATE
operacja jest wykonywana podczas opróżniania kontekstu trwałego, tuż przed zatwierdzeniem, i dlategoUpdating the Book entity
wiadomość jest najpierw logowana.Używanie w
@SelectBeforeUpdate
celu uniknięcia niepotrzebnych aktualizacjiTeraz UPDATE zawsze będzie wykonywane, nawet jeśli jednostka nie została zmieniona w stanie odłączonym. Aby temu zapobiec, możesz użyć
@SelectBeforeUpdate
adnotacji Hibernacja, która uruchomiSELECT
pobrane polecenieloaded state
która zostanie następnie wykorzystana przez mechanizm sprawdzania nieczystości.Jeśli więc dodamy adnotację do
Book
jednostki za pomocą@SelectBeforeUpdate
adnotacji:I wykonaj następujący przypadek testowy:
Hibernacja wykonuje następujące instrukcje SQL:
Zauważ, że tym razem nie jest
UPDATE
wykonywane, ponieważ mechanizm hibernacji „brudnego sprawdzania” wykrył, że jednostka nie została zmodyfikowana.SaveOrUpdate
saveOrUpdate
Metoda specyficzna dla hibernacji jest tylko aliasem dlasave
iupdate
.Teraz możesz użyć,
saveOrUpdate
gdy chcesz utrwalić byt lub wymusić element,UPDATE
jak pokazano w poniższym przykładzie.Uważaj na
NonUniqueObjectException
Jednym z problemów, który może wystąpić z
save
,update
isaveOrUpdate
jest, jeśli kontekst trwałości zawiera już odwołanie do jednostki o tym samym identyfikatorze i tego samego typu, jak w poniższym przykładzie:Teraz, wykonując powyższy przypadek testowy, Hibernacja rzuci a,
NonUniqueObjectException
ponieważ drugiEntityManager
zawiera jużBook
encję o tym samym identyfikatorze, co ten, który przekazujemyupdate
, a kontekst trwałości nie może przechowywać dwóch reprezentacji tej samej encji.Łączyć
Aby tego uniknąć
NonUniqueObjectException
, musisz użyćmerge
metody oferowanej przez JPAEntityManager
i dziedziczonej również przez HibernacjęSession
.Jak wyjaśniono w tym artykule ,
merge
pobiera nową migawkę encji z bazy danych, jeśli w kontekście trwałości nie znaleziono odwołania do encji, i kopiuje stan odłączonej encji przekazanej domerge
metody.Aby zobaczyć, jak
merge
działa metoda, rozważ następujący przykład, który utrzymujeBook
byt w jednej transakcji, a następnie modyfikuje go, gdy jest on w stanie odłączonym, i przekazuje odłączony bytmerge
w podsekwencji Kontekst trwałości.Podczas uruchamiania powyższego przypadku testowego Hibernacja wykonała następujące instrukcje SQL:
Zauważ, że zwrócone przez encję odwołanie do encji
merge
jest inne niż odłączone, które przekazaliśmy domerge
metody.Teraz, chociaż powinieneś preferować używanie JPA
merge
podczas kopiowania stanu odłączonej jednostki, dodatkoweSELECT
mogą być problematyczne podczas wykonywania zadania przetwarzania wsadowego.Z tego powodu powinieneś preferować używanie,
update
gdy masz pewność, że żadne odwołanie do encji nie jest już dołączone do aktualnie działającego kontekstu trwałości i że odłączony byt został zmodyfikowany.Więcej informacji na ten temat można znaleźć w tym artykule .
Wniosek
Aby utrwalić jednostkę, należy użyć
persist
metody JPA . Aby skopiować stan odłączonej jednostki,merge
powinno być preferowane. Taupdate
metoda jest przydatna tylko do zadań przetwarzania wsadowego.save
IsaveOrUpdate
to tylko aliasyupdate
i nie należy ich używać prawdopodobnie w ogóle.Niektórzy programiści dzwonią
save
nawet wtedy, gdy jednostka jest już zarządzana, ale jest to błąd i wyzwala zdarzenie nadmiarowe, ponieważ dla jednostek zarządzanych UPDATE jest automatycznie obsługiwana w czasie opróżniania kontekstu Persistence.Aby uzyskać więcej informacji, sprawdź ten artykuł .
źródło
Należy pamiętać, że jeśli wywołasz aktualizację na odłączonym obiekcie, zawsze nastąpi aktualizacja w bazie danych, niezależnie od tego, czy zmieniłeś obiekt, czy nie. Jeśli nie jest to, czego chcesz, powinieneś użyć Session.lock () z LockMode.None.
Powinieneś wywołać aktualizację tylko wtedy, gdy obiekt został zmieniony poza zakresem bieżącej sesji (w trybie odłączonym).
źródło
Żadna z poniższych odpowiedzi nie jest poprawna. Wszystkie te metody wydają się podobne, ale w praktyce robią absolutnie różne rzeczy. Trudno podać krótkie komentarze. Lepiej podać link do pełnej dokumentacji na temat tych metod: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
źródło
Żadna z powyższych odpowiedzi nie jest kompletna. Chociaż odpowiedź Leo Theobalda wygląda na najbliższą.
Podstawową kwestią jest to, jak hibernacja radzi sobie ze stanami bytów i jak sobie z nimi radzi, gdy następuje zmiana stanu. Wszystko musi być postrzegane również w odniesieniu do flushów i zatwierdzeń, które wszyscy wydają się całkowicie ignorować.
NIGDY NIE UŻYWAJ ZAPISANEJ METODY HIBERNATU. ZAPOMNIJ, ŻE JESZCZE ISTNIEJE W HIBERNATIE!
Trwać
Jak wszyscy wyjaśnili, Persist zasadniczo zmienia byt ze stanu „przejściowego” w stan „zarządzanego”. W tym momencie slush lub zatwierdzenie może utworzyć instrukcję insert. Ale jednostka nadal pozostanie w stanie „Zarządzanym”. To się nie zmienia wraz z kolorami.
W tym momencie, jeśli „uporczywie” ponownie, nie będzie żadnych zmian. I nie będzie już żadnych zapisów, jeśli spróbujemy utrzymać uparty byt.
Zabawa zaczyna się, gdy próbujemy eksmitować istotę.
Eksmisja to specjalna funkcja Hibernacji, która zmieni byt z „Zarządzanego” na „Odłączony”. Nie możemy wywoływać trwałej odłączonej jednostki. Jeśli to zrobimy, Hibernacja zgłosi wyjątek, a cała transakcja zostanie wycofana po zatwierdzeniu.
Scal vs Aktualizacja
Są to 2 ciekawe funkcje, które wykonują różne czynności, gdy są obsługiwane na różne sposoby. Obaj próbują zmienić byt ze stanu „Odłączony” do stanu „Zarządzany”. Ale robi to inaczej.
Zrozum, że Odłączony oznacza rodzaj „offline”. i zarządzany oznacza stan „Online”.
Obserwuj poniższy kod:
Kiedy to robisz? Jak myślisz, co się stanie? Jeśli powiedziałeś, że spowoduje to wyjątek, masz rację. Spowoduje to wyjątek, ponieważ scalanie działało na obiekcie encji, który jest stanem odłączonym. Ale to nie zmienia stanu obiektu.
Za sceną scalenie wywoła wybrane zapytanie i zasadniczo zwraca kopię encji, która jest w stanie dołączonym. Obserwuj poniższy kod:
Powyższa próbka działa, ponieważ scalanie wprowadziło nowy byt w kontekście, który jest w stanie trwałym.
Po zastosowaniu z aktualizacją to samo działa dobrze, ponieważ aktualizacja nie przynosi kopii encji takiej jak scalanie.
Jednocześnie w śledzeniu debugowania widzimy, że aktualizacja nie wywołała zapytania SQL typu select like merge.
usunąć
W powyższym przykładzie użyłem delete bez mówienia o delete. Usuń zasadniczo spowoduje przejście jednostki ze stanu zarządzanego do stanu „usuniętego”. A po opróżnieniu lub zatwierdzeniu wyda polecenie usuwania do zapisania.
Możliwe jest jednak przywrócenie jednostki do stanu „zarządzanego” ze stanu „usuniętego” za pomocą metody persist.
Mam nadzieję, że powyższe wyjaśnienie wyjaśniło wszelkie wątpliwości.
źródło