¿Cuál es la ventaja de persistir () frente a salvar () en Hibernate?

Respuestas:

154

De esta publicación del foro

persist()Está bien definido. Hace que una instancia transitoria sea persistente. Sin embargo, no garantiza que el valor del identificador se asignará a la instancia persistente de inmediato, la asignación puede ocurrir en el momento del vaciado. La especificación no dice eso, que es el problema que tengo persist().

persist()también garantiza que no ejecutará una instrucción INSERT si se llama fuera de los límites de la transacción. Esto es útil en conversaciones de larga duración con un contexto extendido de sesión / persistencia.

Se persist()requiere un método como .

save()no garantiza lo mismo, devuelve un identificador, y si se debe ejecutar un INSERT para obtener el identificador (por ejemplo, generador de "identidad", no "secuencia"), este INSERT se produce de inmediato, sin importar si está dentro o fuera una transacción Esto no es bueno en una conversación de larga duración con un contexto extendido de sesión / persistencia.

Bala R
fuente
44
para agregar más de la misma publicación, para quejarse: "Lamentablemente, 5 años después, este hilo sigue siendo la única fuente clara de información sobre este tema. La documentación de Hibernate, aunque detallada, es nula de toda la información de uso menos trivial. Por qué la última publicación de christian no está en la sesión javadoc es solo otro misterio de la documentación de Hibernate ".
kommradHomer
¿quiere decir que el método persist () hará que la entidad esté en estado separado y save () en estado adjunto?
rekinyz
2
Recientemente utilicé guardar y persistir en un mapeo bidireccional de uno a muchos. descubrí que guardar no cae en cascada para el niño, es decir, solo el padre se guarda / inserta en la tabla. Sin embargo, persistió en la tarea de salvar a ambos padres e hijos en una sola llamada. Estoy usando una identificación compuesta, no una identificación generada.
arn-arn
68

He realizado una buena investigación sobre save () vs persist (), incluida la ejecución en mi máquina local varias veces. Todas las explicaciones anteriores son confusas y no son correctas. Comparé el guardar () y el persistir () a continuación después de una investigación exhaustiva.

Save()

  1. Devuelve ID generado después de guardar. Su Serializabletipo de retorno.
  2. guardar los cambios en la base de datos fuera de la transacción.
  3. Asigna la identificación generada a la entidad que persiste
  4. Session.save () para un objeto separado creará una nueva fila en la tabla.

Persist()

  1. No devuelve el ID generado después de guardar. Su tipo de retorno nulo.
  2. No guarda los cambios en la base de datos fuera de la transacción.
  3. Asigna el generated ida la entidad que persiste
  4. session.persist()para un objeto separado arrojará PersistentObjectExceptionya que no está permitido.

Todos estos son probados / probados Hibernate v4.0.1.

Zeus
fuente
Se menciona el punto 3 para Save () y Persist (), pero en realidad no son lo mismo. El método Persist () guarda los cambios en db fuera de la transacción también.
Ravi.Kumar
2
cuando probé después de confirmar la transacción usando el valor del método persistente no se guarda en DB
Laxminarayana Challagonda
¿Entonces # 1 y # 5 son la verdadera diferencia entre los dos? Si necesita una identificación devuelta o una nueva fila creada, use Save()?
user2490003
Cómo Save () # 3 es posible fuera de la transacción
vikas singh
24

Hice algunas pruebas simuladas para registrar la diferencia entre save()y persist().

Parece que ambos métodos se comportan igual cuando se trata de una entidad transitoria, pero difieren cuando se trata de una entidad separada.

Para el siguiente ejemplo, tome EmployeeVehicle como una Entidad con PK, vehicleIdque es un valor generado y vehicleNamecomo una de sus propiedades.

Ejemplo 1: Manejo de objetos transitorios

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

Resultado:

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

Tenga en cuenta que el resultado es el mismo cuando obtiene un objeto ya persistente y lo guarda

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

Repita lo mismo usando persist(entity)y resultará igual con un nuevo Id (digamos 37, honda);

Ejemplo 2: Tratar con objeto separado

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

Resultado: es posible que espere que el Vehículo con id: 36 obtenido en la sesión anterior se actualice con el nombre "Toyota". Pero lo que sucede es que una nueva entidad se guarda en la base de datos con un nuevo Id generado para y Nombre como "Toyota"

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

Uso de persistir para persistir entidad separada

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

Resultado:

Exception being thrown : detached entity passed to persist

Por lo tanto, siempre es mejor usar Persist () en lugar de Save () ya que guardar debe usarse con cuidado cuando se trata de objetos Transient.

Nota importante: en el ejemplo anterior, el pk de la entidad del vehículo es un valor generado, por lo que cuando se usa save () para persistir una entidad separada, hibernate genera una nueva identificación para persistir. Sin embargo, si este pk no es un valor generado, se genera una excepción que indica la violación de la clave.

Deivanayagam Senthil
fuente
12

Esta pregunta tiene algunas buenas respuestas sobre los diferentes métodos de persistencia en Hibernate. Para responder a su pregunta directamente, con save () la instrucción de inserción se ejecuta inmediatamente, independientemente del estado de la transacción. Devuelve la clave insertada para que pueda hacer algo como esto:

long newKey = session.save(myObj);

Por lo tanto, use save () si necesita un identificador asignado a la instancia persistente de inmediato.

Con persist (), la instrucción de inserción se ejecuta en una transacción, no necesariamente de forma inmediata. Esto es preferible en la mayoría de los casos.

Use persist () si no necesita que la inserción se realice fuera de secuencia con la transacción y no necesita que se devuelva la clave insertada.

CFL_Jeff
fuente
6

Estas son las diferencias que pueden ayudarlo a comprender las ventajas de los métodos de persistencia y guardado:

  • La primera diferencia entre guardar y persistir es su tipo de retorno. El tipo de retorno del método de persistencia es nulo, mientras que el tipo de retorno del
    método de guardar es un objeto serializable.
  • El método persist () no garantiza que el valor del identificador se asignará al estado persistente de inmediato, la asignación puede ocurrir en el momento del vaciado.

  • El método persist () no ejecutará una consulta de inserción si se llama fuera de los límites de la transacción. Mientras, el método save () devuelve un identificador para que una consulta de inserción se ejecute inmediatamente para obtener el identificador, sin importar si está dentro o fuera de una transacción.

  • El método de persistencia se llama fuera de los límites de la transacción, es útil en conversaciones de larga duración con un contexto de sesión extendido. Por otro lado, el método de guardar no es bueno en una conversación de larga duración con un contexto de sesión extendido.

  • Quinta diferencia entre el método guardar y persistir en Hibernate: persist es compatible con JPA, mientras que guardar solo es compatible con Hibernate.

Puede ver el ejemplo de trabajo completo en la publicación Diferencia entre el método de guardar y persistir en Hibernate

David Pham
fuente
Primero dice "El método persist () no ejecutará una consulta de inserción si se llama fuera de los límites de la transacción". Luego dice "El método de persistencia se llama fuera de los límites de transacción, es útil en conversaciones de larga duración con un contexto de sesión extendido". ¿No son contradictorios? No entiendo.
Kumar Manish
@ KumarManish En el caso del método de persistencia, se realiza una consulta de inserción en el momento del vaciado. Entonces, es una práctica recomendada en conversaciones de larga duración
David Pham
5

save (): como sugiere el nombre del método, hibernate save () se puede usar para guardar la entidad en la base de datos. Podemos invocar este método fuera de una transacción. Si usamos esto sin transacción y tenemos una conexión en cascada entre entidades, solo se salvará la entidad primaria a menos que lancemos la sesión.

persistir (): la persistencia de Hibernate es similar a guardar (con transacción) y agrega el objeto de entidad al contexto persistente, por lo que se realiza un seguimiento de cualquier cambio adicional. Si las propiedades del objeto se cambian antes de que se confirme la transacción o se vacíe la sesión, también se guardará en la base de datos. Además, podemos usar el método persist () solo dentro del límite de una transacción, por lo que es seguro y se ocupa de los objetos en cascada. Finalmente, persistir no devuelve nada, por lo que debemos usar el objeto persistente para obtener el valor del identificador generado.

Rohit Goyal
fuente
5

Aquí está la diferencia:

  1. salvar:

    1. devolverá la identificación / identificador cuando el objeto se guarde en la base de datos.
    2. también se guardará cuando se intente que el objeto haga lo mismo al abrir una nueva sesión después de que se separe.
  2. Persistir:

    1. regresará nulo cuando el objeto se guarde en la base de datos.
    2. lanzará PersistentObjectException cuando intente guardar el objeto separado a través de una nueva sesión.
Mohammed Amen
fuente
¿Puedes mostrar un ejemplo con un fragmento? Eso sería útil.
Avikool91
5

La regla básica dice que:

Para entidades con identificador generado:

save (): devuelve el identificador de una entidad inmediatamente además de hacer que el objeto sea persistente. Por lo tanto, una consulta de inserción se activa de inmediato.

persistir (): devuelve el objeto persistente. No tiene ninguna obligación de devolver el identificador de inmediato, por lo que no garantiza que el inserto se disparará de inmediato. Puede disparar un inserto de inmediato, pero no está garantizado. En algunos casos, la consulta puede dispararse inmediatamente, mientras que en otros puede dispararse en el momento de la descarga de la sesión.

Para entidades con identificador asignado:

save (): devuelve el identificador de una entidad de inmediato. Como el identificador ya está asignado a la entidad antes de llamar a guardar, la inserción no se activa de inmediato. Se dispara a la hora de descarga de la sesión.

persistir (): igual que guardar. También dispara el inserto en el momento de descarga.

Supongamos que tenemos una entidad que usa un identificador generado de la siguiente manera:

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

salvar() :

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

persistir ():

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

Ahora suponga que tenemos la misma entidad definida de la siguiente manera sin que el campo id haya generado una anotación, es decir, la ID se asignará manualmente.

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

para guardar ():

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

para persistir ():

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

Los casos anteriores fueron ciertos cuando se llamó a guardar o persistir desde una transacción.

Los otros puntos de diferencia entre guardar y persistir son:

  1. Se puede llamar a save () fuera de una transacción. Si se utiliza el identificador asignado, ya que el ID ya está disponible, por lo que no se activa ninguna consulta de inserción. La consulta solo se activa cuando la sesión se vacía.

  2. Si se utiliza el identificador generado, entonces, dado que la identificación debe generarse, la inserción se dispara inmediatamente. Pero solo salva a la entidad primaria. Si la entidad tiene algunas entidades en cascada, entonces esas no se guardarán en db en este momento. Se guardarán cuando la sesión se vacíe.

  3. Si persist () está fuera de una transacción, la inserción solo se activa cuando se vacía la sesión, sin importar qué tipo de identificador (generado o asignado) se utilice.

  4. Si se llama guardar sobre un objeto persistente, la entidad se guarda mediante la consulta de actualización.

Gaurav Kumar
fuente
2

En realidad, la diferencia entre los métodos hibernate save () y persist () depende de la clase de generador que estemos usando.
Si se asigna nuestra clase de generador, entonces no hay diferencia entre los métodos save () y persist (). Debido a que el generador 'asignado' significa, como programador necesitamos dar el valor de la clave primaria para guardarlo en la base de datos correcta [Espero que conozca este concepto de generador] hibernate en sí asignará el valor de ID de la clave primaria a la base de datos [aparte del generador asignado, hibernate solo se usa para cuidar el valor de ID de la clave primaria recordar], así que en este caso si llamamos al método save () o persist (), entonces insertará el registro en la base de datos normalmente.
Pero aquí, lo que pasa es que el método save () puede devolver el valor de identificación de la clave primaria que genera hibernate y podemos verlo por
s = session.save (k);
En este mismo caso, persist () nunca devolverá ningún valor al cliente, devuelve el tipo void.
persist () también garantiza que no ejecutará una instrucción INSERT si se llama fuera de los límites de la transacción.
mientras que en save (), INSERT ocurre inmediatamente, sin importar si está dentro o fuera de una transacción.

Hari Krishna
fuente
1

Respondió completamente sobre la base del tipo de "generador" en la identificación mientras almacenaba cualquier entidad. Si el valor para el generador está "asignado", lo que significa que está proporcionando la ID. Entonces no hace diferencia en hibernar para guardar o persistir. Puedes ir con cualquier método que desees. Si el valor no está "asignado" y está utilizando save (), obtendrá la ID como retorno de la operación save ().

Otra comprobación es si está realizando la operación fuera del límite de transacción o no. Porque persist () pertenece a JPA mientras save () para hibernar. Por lo tanto, el uso de persist () fuera de los límites de la transacción no permitirá hacerlo y generará excepciones relacionadas con persistente. mientras que con save () no existe tal restricción y uno puede ir con la transacción DB a través de save () fuera del límite de la transacción.

Neeraj
fuente