Ответы:
persist()
хорошо определено. Это делает временный экземпляр постоянным. Однако это не гарантирует, что значение идентификатора будет назначено постоянному экземпляру немедленно, назначение может произойти во время сброса. В спецификации это не сказано, с чем у меня проблемаpersist()
.
persist()
также гарантирует, что он не будет выполнять инструкцию INSERT, если он вызывается вне границ транзакции. Это полезно в длительных беседах с расширенным контекстом сеанса / постоянства.Такой метод, как
persist()
требуется.
save()
не гарантирует то же самое, он возвращает идентификатор, и если для получения идентификатора необходимо выполнить INSERT (например, генератор «identity», а не «sequence»), эта INSERT происходит немедленно, независимо от того, находитесь вы внутри или снаружи сделка Это не хорошо в длительном разговоре с расширенным контекстом сеанса / постоянства.
Я провел хорошее исследование save () и persist (), включая запуск его на моей локальной машине несколько раз. Все предыдущие объяснения сбивают с толку и не являются правильными. Я сравнил save () и persist () ниже после тщательного исследования.
Save()
Serializable
тип возвращаемого значения .Persist()
generated id
сущность, которую вы сохраняетеsession.persist()
за оторванный объект выбросит так PersistentObjectException
как это не разрешено.Все это проверено / опробовано Hibernate v4.0.1
.
Save()
?
Я сделал некоторые издеваться тестирование , чтобы записать разницу между 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 не является сгенерированным значением, это приведет к нарушению ключа, указывающего на исключение.
Этот вопрос имеет несколько хороших ответов о различных методах сохранения в Hibernate. Чтобы ответить на ваш вопрос напрямую, с помощью save () оператор вставки выполняется немедленно, независимо от состояния транзакции. Он возвращает вставленный ключ, чтобы вы могли сделать что-то вроде этого:
long newKey = session.save(myObj);
Поэтому используйте save (), если вам нужен идентификатор, назначенный постоянному экземпляру немедленно.
С помощью persist () оператор вставки выполняется в транзакции, а не обязательно сразу. Это предпочтительнее в большинстве случаев.
Используйте persist (), если вам не нужно, чтобы вставка происходила вне последовательности транзакции, и вам не нужен возвращенный вставленный ключ.
Вот различия, которые могут помочь вам понять преимущества методов сохранения и сохранения:
Метод persist () не гарантирует, что значение идентификатора будет немедленно присвоено постоянному состоянию, назначение может произойти во время сброса.
Метод persist () не выполнит запрос вставки, если он вызывается вне границ транзакции. В то время как метод save () возвращает идентификатор, так что запрос вставки выполняется немедленно для получения идентификатора, независимо от того, находится ли он внутри или вне транзакции.
Метод persist вызывается вне границ транзакции, он полезен в длительных беседах с расширенным контекстом сеанса. С другой стороны, метод сохранения не годится в длительном диалоге с расширенным контекстом сеанса.
Пятое различие между методом сохранения и сохранением в Hibernate: постоянство поддерживается JPA, в то время как сохранение поддерживается только Hibernate.
Вы можете увидеть полный рабочий пример из поста Разница между сохранением и сохранением метода в Hibernate
save () - Как следует из названия метода, hibernate save () может использоваться для сохранения объекта в базе данных. Мы можем вызвать этот метод вне транзакции. Если мы используем это без транзакции, и у нас есть каскад между сущностями, то сохраняется только основная сущность, если мы не очистим сеанс.
persist () - Hibernate persist похож на save (с транзакцией) и добавляет объект сущности в постоянный контекст, поэтому любые дальнейшие изменения отслеживаются. Если свойства объекта изменяются до фиксации транзакции или сброса сеанса, он также будет сохранен в базе данных. Кроме того, мы можем использовать метод persist () только в пределах границы транзакции, поэтому он безопасен и заботится о любых каскадных объектах. Наконец, persist ничего не возвращает, поэтому нам нужно использовать постоянный объект, чтобы получить сгенерированное значение идентификатора.
Вот разница:
спасти:
Упорство:
Основное правило гласит:
Для сущностей с сгенерированным идентификатором:
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 вызывались из транзакции.
Другие отличия между сохранением и сохранением:
save () может вызываться вне транзакции. Если назначенный идентификатор используется, то, поскольку идентификатор уже доступен, поэтому запрос вставки не запускается немедленно. Запрос запускается только тогда, когда сеанс сбрасывается.
Если используется сгенерированный идентификатор, то, поскольку id нужно сгенерировать, вставка сразу запускается. Но это только спасает первичную сущность. Если у сущности есть несколько каскадных сущностей, то они не будут сохранены в БД на данный момент. Они будут сохранены, когда сессия сброшена.
Если persist () находится за пределами транзакции, вставка запускается только при сбросе сеанса независимо от того, какой тип идентификатора (сгенерированный или назначенный) используется.
Если сохранение вызывается для постоянного объекта, то объект сохраняется с помощью запроса на обновление.
На самом деле, разница между методами hibernate save () и persist () зависит от класса генератора, который мы используем.
Но здесь дело в том, что метод save () может возвращать значение идентификатора первичного ключа, сгенерированное hibernate, и мы можем увидеть его по
длинным s = session.save (k);
В этом же случае, persist () никогда не вернет клиенту никакого значения, тип возврата void.
Функция persist () также гарантирует, что она не выполнит инструкцию INSERT, если она вызывается вне границ транзакции.
тогда как в save () INSERT происходит немедленно, независимо от того, находитесь ли вы внутри или вне транзакции.
Если наш класс генератора назначен, то нет никакой разницы между методами save () и persist (). Поскольку генератор «назначен» означает, что как программисту нам нужно дать значение первичного ключа для сохранения в праве на базу данных [Надеюсь, вы знакомы с этой концепцией генераторов] В случае, если класс генератора не назначен, предположим, что имя нашего класса генератора равно «Приращение» означает hibernate сам назначит значение идентификатора первичного ключа в праве базы данных [кроме назначенного генератора, hibernate используется только для обеспечения запоминания значения идентификатора первичного ключа], поэтому в этом случае, если мы вызовем метод save () или persist (), тогда он вставит запись в базу данных в обычном режиме.
Он полностью ответил на основе типа «генератора» в идентификаторе при сохранении любой сущности. Если значение для генератора «назначено», это означает, что вы предоставляете идентификатор. Тогда он не делает различий в спящем режиме для сохранения или сохранения. Вы можете пойти любым способом, который вы хотите. Если значение не «назначено» и вы используете save (), вы получите идентификатор в качестве возврата из операции save ().
Другая проверка заключается в том, выполняете ли вы операцию вне предела транзакции или нет. Потому что persist () принадлежит JPA, а save () для спящего. Поэтому использование persist () вне границ транзакции не позволит сделать это и выдает исключение, связанное с persistant. в то время как с save () такого ограничения нет, и можно выполнить транзакцию с БД через save () вне предела транзакции.