В чем преимущество функции persist () и save () в Hibernate? - PullRequest
152 голосов
/ 03 мая 2011

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

Ответы [ 10 ]

144 голосов
/ 03 мая 2011

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

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

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

Требуется метод, подобный persist().

save() не гарантирует то же самое, это возвращает идентификатор, и если ВСТАВКА должна быть выполнена, чтобы получить идентификатор (например, генератор «идентичности», не "последовательность"), эта вставка происходит немедленно, независимо от того, если вы внутри или вне транзакции. Это не хорошо в долгосрочной перспективе разговор с расширенным Контекст сеанса / постоянства.

58 голосов
/ 23 февраля 2015

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

Save()

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

Persist()

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

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

23 голосов
/ 26 июля 2013

Я провел некоторое пробное тестирование, чтобы записать разницу между 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) и получитерезультат тот же с новым идентификатором (скажем, 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 не является сгенерированным значением, это приведет к нарушению ключа, указывающего на исключение.

12 голосов
/ 06 марта 2012

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

long newKey = session.save(myObj);

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

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

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

5 голосов
/ 24 октября 2016

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

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

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

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

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

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

5 голосов
/ 20 апреля 2015

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

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

4 голосов
/ 28 января 2017

Вот разница:

  1. save:

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

    1. вернет void при сохранении объекта в базе данных.
    2. вызовет исключение PersistentObjectException при попытке сохранить отсоединенный объект через новый сеанс.
2 голосов
/ 15 июля 2013

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

1 голос
/ 25 июля 2018

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

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

1 голос
/ 01 января 2015

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

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

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

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

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

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

persist (): то же, что и save. Это также стреляет вставкой во время потока.

Предположим, у нас есть объект, который использует сгенерированный идентификатор следующим образом:

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

save ():

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

для 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();

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...