В чем преимущество функции persist () и save () в Hibernate?

162

Может кто-нибудь сказать мне, в чем преимущество persist()против save()Hibernate?

Антонио
источник
10
Смотрите также: В чем преимущество load () перед get () в Hibernate? stackoverflow.com/questions/5370482/…
Антонио

Ответы:

154

Из этого сообщения на форуме

persist()хорошо определено. Это делает временный экземпляр постоянным. Однако это не гарантирует, что значение идентификатора будет назначено постоянному экземпляру немедленно, назначение может произойти во время сброса. В спецификации это не сказано, с чем у меня проблема persist().

persist()также гарантирует, что он не будет выполнять инструкцию INSERT, если он вызывается вне границ транзакции. Это полезно в длительных беседах с расширенным контекстом сеанса / постоянства.

Такой метод, как persist()требуется.

save()не гарантирует то же самое, он возвращает идентификатор, и если для получения идентификатора необходимо выполнить INSERT (например, генератор «identity», а не «sequence»), эта INSERT происходит немедленно, независимо от того, находитесь вы внутри или снаружи сделка Это не хорошо в длительном разговоре с расширенным контекстом сеанса / постоянства.

Бала Р
источник
44
добавить еще из того же поста, чтобы скулить: «К сожалению, 5 лет спустя эта ветка все еще остается единственным ясным источником информации по этому вопросу. Документация Hibernate, хотя и многословна, лишена всей информации, кроме самой тривиальной информации об использовании. Почему последний пост Кристиана отсутствует в Javadoc для Session, это просто еще одна загадка документации Hibernate ».
kommradHomer
Вы имеете в виду, что метод persist () переведет сущность в отдельное состояние, а save () - в присоединенное состояние?
рекиныз
2
Недавно я использовал и сохранить, и сохранить в двунаправленном отображении «один ко многим». я обнаружил, что сохранение не распространяется на ребенка, т. е. в таблицу сохраняется / вставляется только родитель. Тем не менее, persist выполнил задачу сохранения родителя и ребенка за один вызов. Я использую составной идентификатор, а не сгенерированный идентификатор.
Арн-Арн
68

Я провел хорошее исследование save () и persist (), включая запуск его на моей локальной машине несколько раз. Все предыдущие объяснения сбивают с толку и не являются правильными. Я сравнил save () и persist () ниже после тщательного исследования.

Save()

  1. Возвращает сгенерированный идентификатор после сохранения. Его Serializableтип возвращаемого значения .
  2. сохранить изменения в БД вне транзакции.
  3. Назначает сгенерированный идентификатор сущности, которую вы сохраняете
  4. Session.save () для отдельного объекта создаст новую строку в таблице.

Persist()

  1. Не возвращает сгенерированный идентификатор после сохранения. Свой тип возврата void.
  2. Не сохраняет изменения в БД вне транзакции.
  3. Назначает generated idсущность, которую вы сохраняете
  4. session.persist()за оторванный объект выбросит так PersistentObjectExceptionкак это не разрешено.

Все это проверено / опробовано Hibernate v4.0.1.

Зевс
источник
Пункт 3 для Save () и Persist () упоминается, но на самом деле они не совпадают. Метод Persist () также сохраняет изменения в БД вне транзакции.
Рави.Кумар
2
когда я проверял после совершения транзакции, используя постоянный метод, значение не сохраняется в БД
Laxminarayana Challagonda
Итак, № 1 и № 5 - это реальная разница между ними? Если вам нужен возвращенный идентификатор или создана новая строка, используйте Save()?
user2490003
Как Save () # 3 возможен вне транзакции
Викас Сингх
24

Я сделал некоторые издеваться тестирование , чтобы записать разницу между save()иpersist() .

Похоже, что оба этих метода ведут себя одинаково при работе с Transient Entity, но различаются при работе с Detached Entity.

Для приведенного ниже примера возьмите 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, полученным в предыдущей сессии, будет обновлен с именем «Тойота». Но что происходит, так это то, что в БД сохраняется новый объект с новым идентификатором, сгенерированным для и названным как «Тойота»

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

Использование persist для сохранения отдельного объекта

// (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 (), так как save должен быть осторожным при работе с временным объектом.

Важное примечание: в приведенном выше примере pk объекта транспортного средства является сгенерированным значением, поэтому при использовании save () для сохранения отсоединенного объекта hibernate генерирует новый идентификатор для сохранения. Однако, если этот pk не является сгенерированным значением, это приведет к нарушению ключа, указывающего на исключение.

Deivanayagam Senthil
источник
13

Этот вопрос имеет несколько хороших ответов о различных методах сохранения в Hibernate. Чтобы ответить на ваш вопрос напрямую, с помощью save () оператор вставки выполняется немедленно, независимо от состояния транзакции. Он возвращает вставленный ключ, чтобы вы могли сделать что-то вроде этого:

long newKey = session.save(myObj);

Поэтому используйте save (), если вам нужен идентификатор, назначенный постоянному экземпляру немедленно.

С помощью persist () оператор вставки выполняется в транзакции, а не обязательно сразу. Это предпочтительнее в большинстве случаев.

Используйте persist (), если вам не нужно, чтобы вставка происходила вне последовательности транзакции, и вам не нужен возвращенный вставленный ключ.

CFL_Jeff
источник
6

Вот различия, которые могут помочь вам понять преимущества методов сохранения и сохранения:

  • Первое различие между сохранением и сохранением - это тип возвращаемого значения. Возвращаемый тип метода persist - void, а возвращаемый тип
    метода save - Serializable object.
  • Метод persist () не гарантирует, что значение идентификатора будет немедленно присвоено постоянному состоянию, назначение может произойти во время сброса.

  • Метод persist () не выполнит запрос вставки, если он вызывается вне границ транзакции. В то время как метод save () возвращает идентификатор, так что запрос вставки выполняется немедленно для получения идентификатора, независимо от того, находится ли он внутри или вне транзакции.

  • Метод persist вызывается вне границ транзакции, он полезен в длительных беседах с расширенным контекстом сеанса. С другой стороны, метод сохранения не годится в длительном диалоге с расширенным контекстом сеанса.

  • Пятое различие между методом сохранения и сохранением в Hibernate: постоянство поддерживается JPA, в то время как сохранение поддерживается только Hibernate.

Вы можете увидеть полный рабочий пример из поста Разница между сохранением и сохранением метода в Hibernate

Дэвид Фам
источник
Сначала вы говорите: «Метод persist () не выполнит запрос вставки, если он вызывается вне границ транзакции». Затем вы говорите: «Метод persist вызывается вне границ транзакции, он полезен в длительных беседах с расширенным контекстом сеанса». Разве они не противоречат друг другу? Я не понимаю
Кумар Маниш
@KumarManish В случае использования метода persist запрос на вставку выполняется во время сброса. Так что это лучшие практики в длительных разговорах
Дэвид Фам
5

save () - Как следует из названия метода, hibernate save () может использоваться для сохранения объекта в базе данных. Мы можем вызвать этот метод вне транзакции. Если мы используем это без транзакции, и у нас есть каскад между сущностями, то сохраняется только основная сущность, если мы не очистим сеанс.

persist () - Hibernate persist похож на save (с транзакцией) и добавляет объект сущности в постоянный контекст, поэтому любые дальнейшие изменения отслеживаются. Если свойства объекта изменяются до фиксации транзакции или сброса сеанса, он также будет сохранен в базе данных. Кроме того, мы можем использовать метод persist () только в пределах границы транзакции, поэтому он безопасен и заботится о любых каскадных объектах. Наконец, persist ничего не возвращает, поэтому нам нужно использовать постоянный объект, чтобы получить сгенерированное значение идентификатора.

Рохит Гоял
источник
5

Вот разница:

  1. спасти:

    1. вернет идентификатор / идентификатор, когда объект будет сохранен в базе данных.
    2. также сохранит, когда объект попытается сделать то же самое, открыв новый сеанс после его отсоединения.
  2. Упорство:

    1. вернет void, когда объект будет сохранен в базе данных.
    2. вызовет исключение PersistentObjectException при попытке сохранить отсоединенный объект в новом сеансе.
Мухаммед Аминь
источник
Можете ли вы показать пример с фрагментом. Это было бы полезно.
Avikool91
5

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

Для сущностей с сгенерированным идентификатором:

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

persist (): возвращает постоянный объект. Он не обязан немедленно возвращать идентификатор, поэтому не гарантирует немедленного запуска вставки. Это может немедленно запустить вставку, но это не гарантировано. В некоторых случаях запрос может быть запущен немедленно, а в других - во время сброса сеанса.

Для сущностей с присвоенным идентификатором:

save (): немедленно возвращает идентификатор объекта. Поскольку идентификатор уже назначен объекту до вызова 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();

persist ():

    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 не было сгенерировано аннотации, т.е. 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();

для постоянного ():

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

Вышеуказанные случаи были верны, когда save или persist вызывались из транзакции.

Другие отличия между сохранением и сохранением:

  1. save () может вызываться вне транзакции. Если назначенный идентификатор используется, то, поскольку идентификатор уже доступен, поэтому запрос вставки не запускается немедленно. Запрос запускается только тогда, когда сеанс сбрасывается.

  2. Если используется сгенерированный идентификатор, то, поскольку id нужно сгенерировать, вставка сразу запускается. Но это только спасает первичную сущность. Если у сущности есть несколько каскадных сущностей, то они не будут сохранены в БД на данный момент. Они будут сохранены, когда сессия сброшена.

  3. Если persist () находится за пределами транзакции, вставка запускается только при сбросе сеанса независимо от того, какой тип идентификатора (сгенерированный или назначенный) используется.

  4. Если сохранение вызывается для постоянного объекта, то объект сохраняется с помощью запроса на обновление.

Гаурав Кумар
источник
2

На самом деле, разница между методами hibernate save () и persist () зависит от класса генератора, который мы используем. Но здесь дело в том, что метод save () может возвращать значение идентификатора первичного ключа, сгенерированное hibernate, и мы можем увидеть его по длинным s = session.save (k); В этом же случае, persist () никогда не вернет клиенту никакого значения, тип возврата void. Функция persist () также гарантирует, что она не выполнит инструкцию INSERT, если она вызывается вне границ транзакции. тогда как в save () INSERT происходит немедленно, независимо от того, находитесь ли вы внутри или вне транзакции.
Если наш класс генератора назначен, то нет никакой разницы между методами save () и persist (). Поскольку генератор «назначен» означает, что как программисту нам нужно дать значение первичного ключа для сохранения в праве на базу данных [Надеюсь, вы знакомы с этой концепцией генераторов] В случае, если класс генератора не назначен, предположим, что имя нашего класса генератора равно «Приращение» означает hibernate сам назначит значение идентификатора первичного ключа в праве базы данных [кроме назначенного генератора, hibernate используется только для обеспечения запоминания значения идентификатора первичного ключа], поэтому в этом случае, если мы вызовем метод save () или persist (), тогда он вставит запись в базу данных в обычном режиме.




Хари Кришна
источник
1

Он полностью ответил на основе типа «генератора» в идентификаторе при сохранении любой сущности. Если значение для генератора «назначено», это означает, что вы предоставляете идентификатор. Тогда он не делает различий в спящем режиме для сохранения или сохранения. Вы можете пойти любым способом, который вы хотите. Если значение не «назначено» и вы используете save (), вы получите идентификатор в качестве возврата из операции save ().

Другая проверка заключается в том, выполняете ли вы операцию вне предела транзакции или нет. Потому что persist () принадлежит JPA, а save () для спящего. Поэтому использование persist () вне границ транзакции не позволит сделать это и выдает исключение, связанное с persistant. в то время как с save () такого ограничения нет, и можно выполнить транзакцию с БД через save () вне предела транзакции.

Neeraj
источник