Яка перевага збереження () проти збереження () у сплячому режимі?


Відповіді:


154

З цього повідомлення на форумі

persist()добре визначений. Це робить перехідний екземпляр стійким. Однак це не гарантує, що значення ідентифікатора буде присвоєно стійкому екземпляру негайно, присвоєння може відбутися під час спалаху. Спеціалізація не говорить про це, яка проблема у мене є persist().

persist()також гарантує, що він не виконає оператор INSERT, якщо він викликається поза межами транзакцій. Це корисно в тривалих розмовах із розширеним контекстом сесії / наполегливості.

Необхідний такий спосіб persist().

save()не гарантує того ж, він повертає ідентифікатор, і якщо INSERT повинен бути виконаний, щоб отримати ідентифікатор (наприклад, генератор "ідентифікація", а не "послідовність"), ця ВИСТАВКА відбувається негайно, незалежно від того, знаходитесь ви всередині або зовні транзакція. Це не добре в тривалій розмові з розширеним контекстом сесії / наполегливості.


44
щоб додати ще з того ж допису, щоб скуголити: "На жаль, через 5 років ця тема залишається єдиним чітким джерелом інформації про цю тему. Зимова документація, хоча і багатослівна, є недійсною, окрім найбільш тривіальної інформації про використання. Чому останній пост Крістіана не знаходиться в сесії Javadoc - це ще одна загадка про сплячу документації ".
kommradHomer

ти маєш на увазі метод persist () перетворити сутність у відірваний стан, а зберегти () у приєднаному стані?
rekinyz

2
нещодавно я використовував як збереження, так і збереження в двонаправленому зіставленні для множин. я з'ясував, що збереження не каскадує дитину, тобто в таблицю зберігається / вставляється лише батько. Однак наполегливі виконали завдання врятувати і батьків, і дитину за один дзвінок. Я використовую складений ідентифікатор, а не згенерований ідентифікатор.
arn-arn

68

Я добре провів дослідження збереження () vs persist (), включаючи запуск його на своїй локальній машині кілька разів. Усі попередні пояснення є заплутаними та невірними. Нижче я порівняв збереження () та зберегти () після ретельного дослідження.

Save()

  1. Повертає згенерований Id після збереження. Його Serializableтип повернення.
  2. збережіть зміни в db за межами транзакції.
  3. Призначає згенерований ідентифікатор суті, яку ви зберігаєте
  4. Session.save () для окремого об'єкта створить новий рядок у таблиці.

Persist()

  1. Не повертає створений Id після збереження. Недійсний тип повернення.
  2. Не зберігає зміни в db за межами транзакції.
  3. Призначає generated idособі, яку ви зберігаєте
  4. session.persist()для відірваного предмета буде кидати, PersistentObjectExceptionяк це не дозволено.

Все це випробувано та випробувано на Hibernate v4.0.1.


Згадано пункт 3 для Save () та Persist (), але насправді вони не є однаковими. Метод Persist () також зберігає зміни db за межами транзакції.
Ravi.Kumar

2
коли я перевірений після здійснення транзакції за допомогою методу "
Персист",

Отже, №1 та №5 - реальна різниця між ними? Якщо вам потрібен ідентифікатор, повернутий чи створений новий рядок, використовувати Save()?
user2490003

Як можливо зберегти () №3 за межами транзакції
vikas singh

24

Я зробив кілька макетних тестувань, щоб записати різницю між save()і persist().

Звучить, що обидва ці способи поводяться однаково при роботі з перехідною сутністю, але відрізняються при роботі з окремою сутністю.

Для наведеного нижче прикладу візьміть EmployeeVehicle як сутність з PK, vehicleIdяка є генерованим значенням і vehicleNameяк одну з його властивостей.

Приклад 1: Робота з перехідним об'єктом

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

Результат:

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

Зауважте, результат такий же, коли ви отримуєте вже збережений об'єкт і зберігаєте його

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

Повторіть те саме, використовуючи persist(entity)і отримайте те ж саме з новим Id (скажімо, 37, honda);

Приклад 2: Робота з окремим об'єктом

// 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();

Результат: Можливо, ви очікуєте, що транспортний засіб з ідентифікатором: 36, отриманий у попередньому сеансі, оновлюється назвою "Toyota". Але те, що трапляється, полягає в тому, що в БД зберігається новий об'єкт із новим ідентифікатором, згенерованим для та ім'ям як "Toyota"

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

Використання персисту для збереження відокремленої сутності

// (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();

Результат:

Exception being thrown : detached entity passed to persist

Таким чином, завжди краще використовувати Persist (), а не Save (), оскільки зберегти потрібно обережно, якщо мати справу з тимчасовим об'єктом.

Важлива примітка: У наведеному вище прикладі pk сутності транспортного засобу є генерованим значенням, тому при використанні save () для збереження відокремленої сутності, сплячий режим генерує новий ідентифікатор для збереження. Однак якщо цей pk не є згенерованим значенням, ніж це призводить до винятку, який свідчить про порушення ключа.


13

На це питання є кілька хороших відповідей щодо різних методів стійкості у сплячому режимі. Щоб відповісти на ваше запитання безпосередньо, за допомогою save () оператор вставлення виконується негайно, незалежно від стану транзакції. Він повертає вставлений ключ, щоб ви могли зробити щось подібне:

long newKey = session.save(myObj);

Тому використовуйте save (), якщо вам негайно потрібен ідентифікатор, призначений постійному екземпляру.

З функцією persist () оператор вставлення виконується в транзакції, не обов'язково відразу. Це є переважним у більшості випадків.

Використовуйте persist (), якщо вам не потрібно, щоб вставка відбувалася поза послідовністю транзакції, і вам не потрібно повернути вставлений ключ.


6

Ось відмінності, за допомогою яких можна зрозуміти переваги збереження та збереження методів:

  • Перша різниця між збереженням та збереженням - це їх тип повернення. Тип повернення персистентного методу є недійсним, тоді як тип повернення
    методу збереження - об'єктом, що підтримується.
  • Метод persist () не гарантує, що значення ідентифікатора буде присвоєно стійкому стану негайно, присвоєння може відбутися під час змиву.

  • Метод persist () не виконає запит на вставку, якщо він викликається поза межами транзакцій. Тоді як метод save () повертає ідентифікатор, щоб запит на вставлення виконувався негайно, щоб отримати ідентифікатор, незалежно від того, знаходиться він всередині або поза транзакцією.

  • Персистентний метод називається поза межами транзакцій, він корисний у тривалих розмовах із розширеним контекстом сесії. З іншого боку, метод збереження не є хорошим у тривалій розмові з розширеним контекстом сесії.

  • П'ята різниця між методом збереження та збереження в режимі глибокого сну: збереження підтримується JPA, а збереження підтримується лише в сплячому режимі.

Ви можете побачити повний робочий приклад із публікації Різниця між методом збереження та збереження в режимі глибокого сну


Спочатку ви скажете "Метод persist () не виконає запит на вставку, якщо він викликається поза межами транзакцій". Потім ви говорите: "Персистентний метод називається поза межами транзакцій, він корисний у тривалих розмовах із розширеним контекстом сесії". Хіба вони не суперечать? Я не розумію.
Кумар Маніш

@KumarManish Якщо метод зберігається, запит на вставку відбувається під час змивання. Отже, це найкраща практика в тривалих розмовах
Девід Фем

5

save () - Як підказує назва методу, hibernate save () може бути використаний для збереження об'єкта до бази даних. Ми можемо використовувати цей метод поза транзакцією. Якщо ми використовуємо це без транзакцій, і ми каскадуємо між сутностями, тоді зберігається лише первинний об'єкт, якщо ми не очистимо сеанс.

persist () - Hibernate persist схожий на збереження (з транзакцією), і він додає об'єкт сутності до стійкого контексту, тому відслідковуються будь-які подальші зміни. Якщо властивості об'єкта будуть змінені до здійснення транзакції або очищення сеансу, він також буде збережений у базі даних. Крім того, ми можемо використовувати метод persist () лише в межах транзакції, тому це безпечно і піклується про будь-які каскадні об'єкти. Нарешті, persist нічого не повертає, тому нам потрібно використовувати збережений об'єкт, щоб отримати сформоване значення ідентифікатора.


5

Ось різниця:

  1. зберегти:

    1. поверне ідентифікатор / ідентифікатор, коли об’єкт буде збережено в базі даних.
    2. також буде збережено, коли об'єкт намагається зробити те саме, відкривши новий сеанс після його від'єднання.
  2. Зберігається:

    1. повернеться недійсним, коли об'єкт буде збережено в базі даних.
    2. викине PersistentObjectException, коли спробує зберегти від'єднаний об'єкт через новий сеанс.

Чи можете ви, будь ласка, показати приклад з фрагментом. Це було б корисно.
Avikool91

5

Основне правило говорить, що:

Для організацій із згенерованим ідентифікатором:

save (): одразу повертає ідентифікатор об'єкта на додаток до того, щоб зробити об'єкт стійким. Тож запит на вставлення запускається негайно.

persist (): повертає стійкий об'єкт. У ньому немає примусового повернення ідентифікатора негайно, тому це не гарантує, що вставка буде негайно запущена. Він може негайно випустити вкладку, але це не гарантується. У деяких випадках запит може бути запущений негайно, а в інших він може бути запущений під час сеансу.

Для організацій із призначеним ідентифікатором:

save (): він негайно повертає ідентифікатор організації. Оскільки перед викликом збереження ідентифікатор вже призначений об'єкту, то вставлення не запускається негайно. Він запускається під час сеансу змивання.

persist (): те саме, що зберегти. Він також вистрілює вставку під час змиву.

Припустимо, у нас є сутність, яка використовує згенерований ідентифікатор наступним чином:

@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;
    }
}

зберегти ():

    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();

зберігаються ():

    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();

Тепер припустимо, що у нас є одна і та ж сутність, визначена нижче, без поля ідентифікатора, що генерує анотацію, тобто ID буде присвоєно вручну.

@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;
    }
}

для збереження ():

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();

Вищеописані випадки були справжніми, коли збереження або збереження викликали операцію в межах транзакції.

Інші моменти різниці між збереженням та збереженням:

  1. save () можна викликати поза транзакцією. Якщо використовується призначений ідентифікатор, оскільки ідентифікатор вже доступний, тому запит на вставлення не буде негайно запущено. Запит запускається лише тоді, коли сеанс буде розмитим.

  2. Якщо використовується згенерований ідентифікатор, оскільки оскільки потрібно створити ідентифікатор, вставлення негайно запускається. Але це рятує лише первинну сутність. Якщо в об'єкті є кілька каскадних об'єктів, вони не будуть збережені в db в цей момент. Вони будуть збережені, коли сеанс буде пропущено.

  3. Якщо параметр persist () знаходиться поза транзацією, то вставка видаляється лише при проведенні сеансу, незалежно від типу ідентифікатора (згенерованого чи призначеного).

  4. Якщо збереження викликається над стійким об'єктом, то об'єкт зберігається за допомогою запиту оновлення.


2

Власне, різниця між режимами hibernate save () та persist () залежить від класу генераторів, який ми використовуємо.
Якщо наш клас генератора призначений, то різниці між методами save () та persist () немає. Оскільки генератор "призначений" означає, що як програміст нам потрібно надати значення первинного ключа для збереження в праві бази даних [Сподіваюся, ви знаєте цю концепцію генераторів] У випадку іншого, ніж призначений клас генератора, припустімо, чи ім'я нашого класу генератора - це збільшення hibernate сама присвоїть значення ідентифікатора первинного ключа правій базі даних [окрім призначеного генератора, сплячий режим, який використовується лише для догляду за значенням ідентифікатора первинного ключа, пам'ятайте], тож у цьому випадку, якщо ми зателефонуємо метод save () або persist (), тоді він буде вставляти запис у базу даних звичайно.
Але тут річ полягає в тому, що метод save () може повернути це значення ідентифікатора первинного ключа, яке генерується в сплячому режимі, і ми можемо бачити його
довгим s = session.save (k);
У цьому ж випадку persist () ніколи не поверне клієнту будь-яке значення, тип повернення - недійсний.
persist () також гарантує, що він не буде виконувати оператор INSERT, якщо його викликають поза межами транзакцій.
тоді як в режимі save () INSERT відбувається негайно, незалежно від того, знаходитесь ви всередині або поза трансакцією.


1

Він повністю відповів на основі типу "генератор" в ідентифікаторі під час зберігання будь-якої сутності. Якщо значення для генератора "призначене", це означає, що ви надаєте ідентифікатор. Тоді це не дає різниці в сплячому режимі для збереження чи збереження. Ви можете скористатися будь-яким потрібним вам методом. Якщо значення не "призначене", а ви використовуєте save (), ви отримаєте ідентифікатор як повернення від операції save ().

Ще одна перевірка - чи виконуєте ви операцію поза межами транзакції чи ні. Тому що persist () належить до JPA, а зберегти () для сплячого. Тож використання persist () поза межами транзакцій не дозволить зробити це та викине виняток, пов’язаний із стійким. в той час як для save () такого обмеження немає, і ви можете перейти з транзакцією DB через save () поза межами транзакції

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.