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

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

10 ответов

Решение

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

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

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

Метод как persist() необходимо.

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

Я провел хорошее исследование 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,

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

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

Вот разница:

  1. спасти:

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

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

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

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам