Jakie są różnice pomiędzy różnymi metodami zapisu w Hibernate?

Hibernate ma kilka metod, które w ten czy inny sposób biorą Twój obiekt i umieszczają go w bazie danych. Jakie są różnice między nimi, kiedy używać czego i dlaczego nie ma tylko jednej inteligentnej metody, która wie, kiedy używać czego?

Metody, które zidentyfikowałem do tej pory to:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()
Author: shA.t, 2008-10-02

8 answers

Oto moje zrozumienie metod. Głównie są one oparte na API , choć nie używam ich wszystkich w praktyce.

SaveOrUpdate Wywołania save lub update w zależności od niektórych kontroli. Np. jeśli nie istnieje żaden identyfikator, wywoływany jest save. W przeciwnym razie wywoływana jest aktualizacja.

Zapisz / Align = "left" / Przypisze identyfikator, jeśli taki nie istnieje. Jeśli tak, to zasadniczo robi aktualizację. Zwraca wygenerowany identyfikator / align = "left" /

Update Próbuje utrzymać jednostkę przy użyciu istniejącego identyfikatora. Jeśli nie istnieje żaden identyfikator, uważam, że wyjątek jest wyrzucany.

SaveOrUpdateCopy Jest to przestarzałe i nie powinno być już używane. Zamiast tego jest...

Merge Teraz moja wiedza zaczyna słabnąć. Ważną rzeczą jest tutaj różnica między bytami przejściowymi, odłączonymi i trwałymi. Aby uzyskać więcej informacji na temat Stanów obiektu, zajrzyj tutaj . Z save & update masz do czynienia z trwałymi obiektami. Są one połączone z sesją, więc Hibernate wie, co się zmieniło. Ale gdy masz obiekt przejściowy, nie ma żadnej sesji. W takich przypadkach musisz użyć merge do aktualizacji i persist do zapisywania.

Persist Jak wspomniano powyżej, jest to używane na obiektach przejściowych. Nie zwraca wygenerowanego identyfikatora.

 109
Author: Lee Theobald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-18 20:10:15
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    METHOD    ║            TRANSIENT          ║            DETACHED            ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id if doesn't      ║   sets new id even if object   ║
║    save()    ║     exist, persists to db,    ║    already has it, persists    ║
║              ║    returns attached object    ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id on object       ║             throws             ║
║   persist()  ║     persists object to DB     ║       PersistenceException     ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║   update()   ║           Exception           ║     persists and reattaches    ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║  copy the state of object in  ║    copy the state of obj in    ║
║    merge()   ║     DB, doesn't attach it,    ║      DB, doesn't attach it,    ║
║              ║    returns attached object    ║     returns attached object    ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║saveOrUpdate()║           as save()           ║            as update()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
 111
Author: Sergii Shevchyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-03 20:30:57
  • Zajrzyj na forum Hibernate Aby uzyskać wyjaśnienie subtelnych różnic między persist i save. Wygląda na to, że różnica polega na czasie, w którym polecenie INSERT zostanie ostatecznie wykonane. Ponieważ save zwraca identyfikator, instrukcja INSERT musi zostać wykonana natychmiast, niezależnie od stanu transakcji(co na ogół jest złe). Persist nie wykona żadnych poleceń poza aktualnie wykonywaną transakcją, tylko po to, aby przypisać identyfikator. Save / Persist oba działają na instancjach przejściowych , czyli instancjach, które nie mają jeszcze przypisanego identyfikatora i jako takie nie są zapisywane w DB.

  • Update i Merge oba działają na odłączonych instancjach , tj. instancjach, które mają odpowiedni wpis w DB, ale które obecnie nie są dołączone (ani nie są zarządzane) przez sesję. Różnica między nimi polega na tym, co dzieje się z instancją przekazywaną do funkcji. update próbuje ponownie podłączyć instancję, co oznacza, że nie może być w tej chwili żadnej innej instancji trwałej jednostki dołączonej do sesji, w przeciwnym razie zostanie wyrzucony wyjątek. merge, jednak po prostu kopiuje wszystkie wartości do trwałej instancji w sesji (która zostanie załadowana, jeśli nie jest aktualnie załadowana). Obiekt wejściowy nie jest zmieniany. Tak więc merge jest bardziej ogólne niż update, ale może wykorzystywać więcej zasobów.

 65
Author: jrudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 09:05:00

Ten link wyjaśnia w dobry sposób:

Http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

Wszyscy mamy te problemy, które napotykamy na tyle rzadko, że kiedy widzimy je ponownie, wiemy, że rozwiązaliśmy to, ale nie pamiętamy jak.

NonUniqueObjectException rzucane podczas korzystania z sesji.saveOrUpdate () w Hibernate jest jednym z moich. Dodam nową funkcjonalność do złożonej aplikacji. Wszystkie moje testy jednostkowe działają dobrze. Następnie podczas testowania interfejsu użytkownika, próbując zapisać obiekt, zaczynam otrzymywać wyjątek z Komunikatem "inny obiekt o tej samej wartości identyfikatora był już skojarzony z sesją."Oto przykładowy kod z Java Persistence z Hibernate.

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

Aby zrozumieć przyczynę tego wyjątku, ważne jest, aby zrozumieć odłączone obiekty i co się dzieje, gdy wywołujesz saveOrUpdate () (lub po prostu update ()) na odłączonym obiekcie.

Kiedy zamykamy jednostkę Sesja Hibernate, trwałe obiekty, z którymi pracujemy, są odłączone. Oznacza to, że dane są nadal w pamięci aplikacji, ale Hibernate nie jest już odpowiedzialny za śledzenie zmian w obiektach.

Jeśli następnie zmodyfikujemy nasz odłączony obiekt i chcemy go zaktualizować, musimy go ponownie podłączyć. Podczas tego procesu, Hibernate sprawdzi, czy nie ma innych kopii tego samego obiektu. Jeśli znajdzie jakąś, musi nam powiedzieć, że nie wie, co to jest "prawdziwa" Kopia już jest. Być może wprowadzono inne zmiany w tych innych kopiach, które spodziewamy się zapisać, ale Hibernate o nich nie wie, ponieważ nie zarządzał nimi w tym czasie.

Zamiast zapisywać potencjalnie złe dane, Hibernate informuje nas o problemie poprzez NonUniqueObjectException.

Więc co robimy? W Hibernate 3 mamy merge () (w Hibernate 2 Użyj saveOrUpdateCopy ()). Ta metoda zmusi Hibernate do skopiowania wszelkich zmian z innych odłączonych instancji na instancja, którą chcesz zapisać, a tym samym łączy wszystkie zmiany w pamięci przed zapisem.
        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

Ważne jest, aby pamiętać, że merge zwraca odniesienie do nowo zaktualizowanej wersji instancji. Nie jest to ponowne dołączanie elementu do sesji. Jeśli przetestujesz na przykład equality (item = = item3), okaże się, że zwraca false w tym przypadku. Prawdopodobnie będziesz chciał pracować z item3 od tego momentu.

Ważne jest również, aby pamiętać, że Java Persistence API (JPA) nie ma koncepcja odłączonych i ponownie dołączonych obiektów i używa EntityManager.persist() i EntityManager.merge ().

Ogólnie stwierdziłem, że podczas używania Hibernate, saveOrUpdate () jest zazwyczaj wystarczające dla moich potrzeb. Zwykle muszę używać funkcji merge tylko wtedy, gdy mam obiekty, które mogą mieć odniesienia do obiektów tego samego typu. Ostatnio przyczyną wyjątku było w kodzie sprawdzanie poprawności, że odwołanie nie było rekurencyjne. Ładowałem ten sam obiekt do mojej sesji w ramach Walidacja, powodująca błąd.

Gdzie napotkałeś ten problem? Czy scalanie działa dla Ciebie, czy potrzebujesz innego rozwiązania? Czy wolisz zawsze używać merge, czy wolisz używać go tylko w razie potrzeby dla konkretnych przypadków
 11
Author: HakunaMatata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-15 13:02:50

W rzeczywistości różnica między metodami hibernate save() i persist() zależy od klasy generatora, której używamy.

Jeśli przypisana jest nasza klasa generatora, to nie ma różnicy między metodami save() i persist(). Ponieważ generator "przypisany" oznacza, jako programista musimy podać podstawową wartość klucza, aby zapisać w bazie danych w prawo [ mam nadzieję, że znasz tę koncepcję generatorów ] W przypadku innej niż przypisana klasy generatora, Załóżmy, że nasza klasa generatora to Increment oznacza hibernate it self przypisze wartość ID klucza podstawowego do bazy danych w prawo [poza przypisanym generatorem, hibernate służy tylko do dbania o zapamiętanie wartości ID klucza podstawowego], więc w tym przypadku jeśli wywołamy metodę save() lub persist(), to wstawi rekord do bazy danych normalnie Ale słyszałem, że metoda save() może zwrócić wartość ID klucza podstawowego, która jest generowana przez hibernate i możemy ją zobaczyć przez

long s = session.save(k);

W tym samym przypadku persist() nigdy nie zwróci żadnej wartości klient.

 4
Author: Hari Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-11 08:07:41

Znalazłem dobry przykład pokazujący różnice pomiędzy wszystkimi metodami zapisu hibernate:

Http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

W skrócie, zgodnie z powyższym linkiem:

Zapisz()

  • możemy wywołać tę metodę poza transakcją. Jeśli użyjemy tego bez transakcji i mamy kaskadowe między encjami, wtedy tylko element podstawowy zostanie zapisany, chyba że spłukamy sesja.
  • Tak więc, jeśli istnieją inne obiekty zmapowane z głównego obiektu, są one zapisywane w momencie zatwierdzania transakcji lub podczas spłukiwania sesji.

Persist()

  • jest podobny do użycia save () w transakcji, więc jest bezpieczny i zajmuje się kaskadowymi obiektami.

SaveOrUpdate()

  • Może być używany z transakcją lub bez niej i podobnie jak save (), jeśli jest używany bez transakcji, zmapowane byty nie będą zapisywane bez; ESS spłukujemy sesję.

  • Wyniki w zapytaniach insert lub update na podstawie dostarczonych danych. Jeśli dane są obecne w bazie danych, wykonywane jest zapytanie update.

Aktualizacja()

  • Aktualizacja Hibernate powinna być używana tam, gdzie wiemy, że aktualizujemy tylko informacje o encji. Ta operacja dodaje obiekt entity do trwałego kontekstu, a dalsze zmiany są śledzone i zapisywane, gdy transakcja jest zaangażowana.
  • stąd nawet po wywołaniu update, jeśli ustawimy jakieś wartości w encji, będą one aktualizowane podczas zatwierdzania transakcji.

Merge()

  • Hibernate merge można użyć do aktualizacji istniejących wartości, jednak ta metoda tworzy kopię z przekazanego obiektu encji i zwraca ją. Zwracany obiekt jest częścią trwałego kontekstu i śledzony dla wszelkich zmian, przekazany obiekt nie jest śledzony. Jest to zasadnicza różnica w merge () od wszystkich innych metody.

Również praktyczne przykłady tych wszystkich, proszę odnieść się do linku, o którym wspomniałem powyżej, pokazuje przykłady dla wszystkich tych różnych metod.

 4
Author: OutOfMind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-12 06:53:11

Należy pamiętać, że jeśli wywołasz update na odłączonym obiekcie, zawsze będzie aktualizacja wykonana w bazie danych, niezależnie od tego, czy zmieniłeś obiekt, czy nie. Jeśli nie jest to, czego chcesz, powinieneś użyć sesji.lock () z LockMode.Brak

Należy wywołać update tylko wtedy, gdy obiekt został zmieniony poza zakresem bieżącej sesji (w trybie odłączonym).

 2
Author: bernardn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-03 12:13:20

Żadna z poniższych odpowiedzi nie jest prawidłowa. Wszystkie te metody wydają się być podobne, ale w praktyce robią zupełnie inne rzeczy. Trudno dać krótkie komentarze. Lepiej dać link do pełnej dokumentacji na temat tych metod: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

 1
Author: Anton Popovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-26 10:38:45