Jaka jest zaleta persist () vs save () w Hibernate?

Odpowiedzi:

154

Z tego posta na forum

persist()jest dobrze zdefiniowany. Sprawia, że ​​przejściowe wystąpienie jest trwałe. Jednak nie gwarantuje, że wartość identyfikatora zostanie natychmiast przypisana do trwałego wystąpienia, przypisanie może nastąpić w czasie opróżniania. Specyfikacja tego nie mówi, z czym mam problem persist().

persist()gwarantuje również, że nie wykona instrukcji INSERT, jeśli zostanie wywołana poza granicami transakcji. Jest to przydatne w długotrwałych konwersacjach z rozszerzonym kontekstem sesji / trwałości.

Taka metoda persist()jest wymagana.

save()nie gwarantuje tego samego, zwraca identyfikator, a jeśli w celu uzyskania identyfikatora ma zostać wykonany INSERT (np. generator „tożsamości”, a nie „sekwencja”), to INSERT następuje natychmiast, bez względu na to, czy jesteś w środku, czy na zewnątrz transakcja. To nie jest dobre w długotrwałej konwersacji z rozszerzonym kontekstem sesji / trwałości.

Bala R
źródło
44
aby dodać więcej z tego samego postu, skomleć: „Niestety, 5 lat później, ten wątek nadal pozostaje jedynym jasnym źródłem informacji na ten temat. Dokumentacja Hibernate, choć pełna, jest pozbawiona wszystkich, z wyjątkiem najbardziej trywialnych informacji dotyczących użytkowania. Dlaczego ostatniego posta Christiana nie ma w Session javadoc, to tylko kolejna tajemnica dokumentacji Hibernate. ”
kommradHomer
czy masz na myśli to, że metoda persist () spowoduje, że jednostka będzie w stanie odłączonym, a save () w stanie dołączonym?
rekinyz
2
Niedawno użyłem zapisywania i utrwalania w dwukierunkowym mapowaniu jeden do wielu. Dowiedziałem się, że zapisywanie nie przechodzi kaskadowo do dziecka, tj. tylko Rodzic jest zapisywany / wstawiany do tabeli. Jednak wytrwały wykonał zadanie ratowania Rodzica i Dziecka w jednej rozmowie. Używam identyfikatora złożonego, a nie wygenerowanego identyfikatora.
arn-arn
68

Zrobiłem dobre badania dotyczące metody save () vs persist (), w tym kilka razy uruchamiając ją na moim komputerze lokalnym. Wszystkie poprzednie wyjaśnienia są mylące i nie są poprawne. Po dokładnym zbadaniu porównałem opcje save () i persist ()).

Save()

  1. Zwraca wygenerowany identyfikator po zapisaniu. Jego Serializabletyp zwrotu.
  2. zapisz zmiany w bazie danych poza transakcją.
  3. Przypisuje wygenerowany identyfikator do jednostki, którą utrwalasz
  4. Session.save () dla odłączonego obiektu utworzy nowy wiersz w tabeli.

Persist()

  1. Po zapisaniu nie zwraca wygenerowanego identyfikatora. Jego void return typ.
  2. Nie zapisuje zmian w bazie danych poza transakcją.
  3. Przypisuje generated idpodmiotowi, który utrwalasz
  4. session.persist()dla odłączonego obiektu będzie rzucać, PersistentObjectExceptionponieważ jest to niedozwolone.

Wszystkie te są wypróbowane / przetestowane Hibernate v4.0.1.

Zeus
źródło
Punkt 3 dotyczący Save () i Persist () jest wspomniany, ale w rzeczywistości nie są one takie same. Persist () również zapisuje zmiany w db poza transakcją.
Ravi.Kumar
2
gdy testowałem po zatwierdzeniu transakcji metodą
trwałości
Więc # 1 i # 5 to prawdziwa różnica między nimi? Jeśli potrzebujesz zwrotu identyfikatora lub utworzenia nowego wiersza, użyj Save()?
user2490003
Jak Save () # 3 jest możliwy poza transakcją
vikas singh
24

Zrobiłem kilka próbnych testów, aby zarejestrować różnicę między save()i persist().

Wygląda na to, że obie te metody zachowują się tak samo, gdy mamy do czynienia z jednostką przejściową, ale różnią się w przypadku jednostki odłączonej.

W poniższym przykładzie weź EmployeeVehicle jako jednostkę z PK jako vehicleIdwygenerowaną wartością i vehicleNamejedną z jej właściwości.

Przykład 1: Radzenie sobie z przejściowym obiektem

Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = new EmployeeVehicle();
entity.setVehicleName("Honda");
session.save(entity);
// session.persist(entity);
session.getTransaction().commit();
session.close();

Wynik:

select nextval ('hibernate_sequence') // This is for vehicle Id generated : 36
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Honda, 36)

Zwróć uwagę, że wynik jest taki sam, gdy otrzymasz już utrwalony obiekt i zapiszesz go

EmployeeVehicle entity =  (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
entity.setVehicleName("Toyota");
session.save(entity);    -------> **instead of session.update(entity);**
// session.persist(entity);

Powtórz to samo użycie persist(entity)i spowoduje to samo z nowym Id (powiedzmy 37, honda);

Przykład 2: Radzenie sobie z odłączonym obiektem

// Session 1 
// Get the previously saved Vehicle Entity 
Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
session.close();

// Session 2
// Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
// (i) Using Save() to persist a detached object 
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.save(entity);
session2.getTransaction().commit();
session2.close();

Wynik: Możesz oczekiwać, że pojazd o identyfikatorze: 36 otrzymany w poprzedniej sesji zostanie zaktualizowany o nazwę „Toyota”. Ale dzieje się tak, że w bazie danych zapisywana jest nowa jednostka z nowym identyfikatorem wygenerowanym dla i nazwą „Toyota”

select nextval ('hibernate_sequence')
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)

Używanie trwałego do utrwalania odłączonej jednostki

// (ii) Using Persist()  to persist a detached
// Session 1 
Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
session.close();

// Session 2
// Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
// (i) Using Save() to persist a detached
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.persist(entity);
session2.getTransaction().commit();
session2.close();

Wynik:

Exception being thrown : detached entity passed to persist

Dlatego zawsze lepiej jest używać Persist () niż Save (), ponieważ save należy używać ostrożnie, gdy mamy do czynienia z obiektem Transient.

Ważna uwaga: W powyższym przykładzie pk jednostki pojazdu jest wygenerowaną wartością, więc gdy używasz save () do utrwalenia odłączonej jednostki, hibernacja generuje nowy identyfikator, aby zachować. Jeśli jednak ten pakiet nie jest wygenerowaną wartością, to skutkuje to wyjątkiem stwierdzającym, że klucz został naruszony.

Deivanayagam Senthil
źródło
13

Na to pytanie można znaleźć dobre odpowiedzi dotyczące różnych metod trwałości w Hibernate. Aby odpowiedzieć bezpośrednio na Twoje pytanie, za pomocą funkcji save () instrukcja wstawiania jest wykonywana natychmiastowo, niezależnie od stanu transakcji. Zwraca wstawiony klucz, więc możesz zrobić coś takiego:

long newKey = session.save(myObj);

Dlatego użyj metody save (), jeśli potrzebujesz natychmiastowego identyfikatora przypisanego do instancji trwałej.

W przypadku persist () instrukcja insert jest wykonywana w transakcji, niekoniecznie natychmiast. W większości przypadków jest to preferowane.

Użyj persist (), jeśli nie potrzebujesz, aby wstawianie było wykonywane poza kolejnością z transakcją i nie potrzebujesz zwróconego wstawionego klucza.

CFL_Jeff
źródło
6

Oto różnice, które mogą pomóc w zrozumieniu zalet metod utrwalania i zapisywania:

  • Pierwszą różnicą między zapisywaniem a utrwalaniem jest ich typ zwracania. Zwracanym typem metody utrwalania jest void, podczas gdy typem zwracanym
    metody zapisywania jest obiekt Serializable.
  • Metoda persist () nie gwarantuje, że wartość identyfikatora zostanie natychmiast przypisana do stanu trwałego, przypisanie może nastąpić w czasie opróżniania.

  • Metoda persist () nie wykona zapytania wstawiającego, jeśli zostanie wywołana poza granicami transakcji. Podczas gdy metoda save () zwraca identyfikator, więc zapytanie wstawiające jest wykonywane natychmiast w celu uzyskania identyfikatora, bez względu na to, czy znajduje się w transakcji, czy poza nią.

  • Metoda utrwalania jest wywoływana poza granicami transakcji, jest przydatna w długotrwałych konwersacjach z rozszerzonym kontekstem sesji. Z drugiej strony metoda save nie jest dobra w długotrwałej konwersacji z rozszerzonym kontekstem sesji.

  • Piąta różnica między metodą zapisywania i utrwalania w Hibernate: persist jest obsługiwana przez JPA, podczas gdy zapisywanie jest obsługiwane tylko przez Hibernate.

Możesz zobaczyć pełny przykład roboczy z postu Różnica między zapisem a utrwalaniem metody w Hibernacji

David Pham
źródło
Najpierw mówisz „Metoda persist () nie wykona zapytania wstawiającego, jeśli zostanie wywołana poza granicami transakcji”. Następnie mówisz „Metoda utrwalania jest wywoływana poza granicami transakcji i jest przydatna w długotrwałych konwersacjach z rozszerzonym kontekstem sesji”. Czy nie są sprzeczne? Nie rozumiem.
Kumar Manish
@KumarManish W przypadku metody utrwalania zapytanie wstawiające następuje w czasie opróżniania. Jest to więc najlepsza praktyka w długotrwałych rozmowach
David Pham
5

save () - Jak sugeruje nazwa metody, hibernacja save () może być użyta do zapisania jednostki do bazy danych. Możemy wywołać tę metodę poza transakcją. Jeśli używamy tego bez transakcji i mamy kaskadowanie między jednostkami, to tylko jednostka podstawowa zostanie zapisana, chyba że opróżnimy sesję.

persist () - Hibernate persist jest podobne do save (with transaction) i dodaje obiekt jednostki do trwałego kontekstu, więc wszelkie dalsze zmiany są śledzone. Jeśli właściwości obiektu zostaną zmienione przed zatwierdzeniem transakcji lub opróżnieniem sesji, zostanie on również zapisany w bazie danych. Ponadto możemy użyć metody persist () tylko w granicach transakcji, więc jest bezpieczna i dba o wszelkie obiekty kaskadowe. Wreszcie, persist nie zwraca niczego, więc musimy użyć utrwalonego obiektu, aby uzyskać wygenerowaną wartość identyfikatora.

Rohit Goyal
źródło
5

Oto różnica:

  1. zapisać:

    1. zwróci identyfikator / identyfikator, gdy obiekt zostanie zapisany w bazie danych.
    2. zapisze również, gdy obiekt spróbuje zrobić to samo, otwierając nową sesję po odłączeniu.
  2. Trwać:

    1. zwróci wartość void, gdy obiekt zostanie zapisany w bazie danych.
    2. wyrzuci PersistentObjectException podczas próby zapisania odłączonego obiektu za pośrednictwem nowej sesji.
Mohammed Amen
źródło
Czy możesz pokazać przykład z fragmentem. To byłoby przydatne.
Avikool91
5

Podstawowa zasada mówi, że:

Dla podmiotów z wygenerowanym identyfikatorem:

save (): Oprócz tego, że obiekt jest trwały, natychmiast zwraca identyfikator jednostki. Więc zapytanie wstawiające jest uruchamiane natychmiast.

persist (): zwraca trwały obiekt. Nie ma obowiązku natychmiastowego zwracania identyfikatora, więc nie gwarantuje, że insert zostanie natychmiast uruchomiony. Może natychmiast odpalić wkładkę, ale nie jest to gwarantowane. W niektórych przypadkach zapytanie może zostać uruchomione natychmiast, podczas gdy w innych może zostać uruchomione w czasie opróżniania sesji.

Dla podmiotów z przypisanym identyfikatorem:

save (): natychmiast zwraca identyfikator jednostki. Ponieważ identyfikator jest już przypisany do jednostki przed wywołaniem save, więc insert nie jest uruchamiany natychmiast. Jest uruchamiany w czasie sesji.

persist (): to samo co save. Wypala również wkładkę w czasie spłukiwania.

Załóżmy, że mamy jednostkę, która używa wygenerowanego identyfikatora w następujący sposób:

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

zapisać() :

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.save(user); // Query is fired immediately as this statement is executed.
    session.getTransaction().commit();
    session.close();

przetrwać ():

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.persist(user); // Query is not guaranteed to be fired immediately. It may get fired here.
    session.getTransaction().commit(); // If it not executed in last statement then It is fired here.
    session.close();

Teraz załóżmy, że mamy tę samą jednostkę zdefiniowaną w następujący sposób, bez pola id, które wygenerowało adnotację, tj. ID zostanie przypisane ręcznie.

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

za zaoszczędzenie ():

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.save(user); // Query is not fired here since id for object being referred by user is already available. No query need to be fired to find it. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();

for persist ():

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.persist(user); // Query is not fired here.Object is made persistent. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();

Powyższe przypadki były prawdziwe, gdy zapisywanie lub utrwalanie zostały wywołane z transakcji.

Inne punkty różnicy między zapisaniem a utrwalaniem to:

  1. Funkcja save () może zostać wywołana poza transakcją. Jeśli używany jest przypisany identyfikator, to ponieważ identyfikator jest już dostępny, więc żadne zapytanie nie jest natychmiast uruchamiane. Zapytanie jest uruchamiane tylko po opróżnieniu sesji.

  2. Jeśli używany jest wygenerowany identyfikator, to ponieważ id trzeba wygenerować, insert jest natychmiast uruchamiany. Ale zapisuje tylko pierwotną jednostkę. Jeśli jednostka ma kilka jednostek kaskadowych, nie zostaną one zapisane w bazie danych w tym momencie. Zostaną zapisane po opróżnieniu sesji.

  3. Jeśli persist () znajduje się poza transakcją, to insert jest uruchamiany tylko wtedy, gdy sesja jest opróżniana, bez względu na rodzaj używanego identyfikatora (wygenerowany lub przypisany).

  4. Jeśli funkcja save jest wywoływana przez trwały obiekt, jednostka jest zapisywana przy użyciu zapytania aktualizującego.

Gaurav Kumar
źródło
2

W rzeczywistości różnica między hibernacją metodami save () i persist () zależy od klasy generatora, którego używamy. Ale tutaj chodzi o to, że metoda save () może zwrócić wartość identyfikatora klucza podstawowego, która jest generowana przez hibernację i możemy to zobaczyć przez long s = session.save (k); W tym samym przypadku persist () nigdy nie zwróci klientowi żadnej wartości, zwracając typ void. persist () gwarantuje również, że nie wykona instrukcji INSERT, jeśli zostanie wywołana poza granicami transakcji. podczas gdy w save (), INSERT dzieje się natychmiast, bez względu na to, czy jesteś w transakcji, czy poza nią.
Jeśli przypisana jest nasza klasa generatora, nie ma różnicy między metodami save () i persist (). Ponieważ generator „przypisany” oznacza, jako programista musimy podać wartość klucza głównego do zapisania w bazie danych w prawo [Mam nadzieję, że znasz tę koncepcję generatorów] W przypadku innej niż przypisana klasa generatora, załóżmy, że nazwa naszej klasy generatora to Przyrost oznacza hibernacja sama przypisze wartość id klucza podstawowego do bazy danych w prawo [inny niż przypisany generator, hibernacja służy tylko do dbania o wartość identyfikatora klucza podstawowego zapamiętaj], więc w tym przypadku, jeśli wywołasz metodę save () lub persist (), to normalnie wstawi rekord do bazy danych.




Hari Krishna
źródło
1

Odpowiadał całkowicie na podstawie identyfikatora typu „generator” podczas przechowywania dowolnego podmiotu. Jeśli wartość dla generatora jest „przypisana”, co oznacza, że ​​podajesz ID. Wtedy nie robi różnicy w hibernacji przy zapisywaniu lub utrwalaniu. Możesz wybrać dowolną metodę. Jeśli wartość nie jest „przypisana” i używasz funkcji save (), otrzymasz identyfikator jako zwrot z operacji save ().

Kolejnym sprawdzeniem jest to, czy wykonujesz operację poza limitem transakcji, czy nie. Ponieważ persist () należy do JPA, a save () na hibernację. Tak więc użycie persist () poza granicami transakcji nie pozwoli na to i zgłosi wyjątek związany z persistant. podczas gdy z save () nie ma takiego ograniczenia i można przejść z transakcją DB przez save () poza limit transakcji.

Neeraj
źródło