ChatGPT解决这个技术问题 Extra ChatGPT

What's the difference between session.persist() and session.save() in Hibernate?

Can anyone tell me what's the advantage of persist() vs save() in Hibernate?

See also: Whats the advantage of load() vs get() in Hibernate?stackoverflow.com/questions/5370482/…
This is one of the latest answers till date by Vlad Mihalcea the author himself. After digging through several old documentation threads, official doc, and many variants on Stack Overflow as well, this is one of the best-curated answers along with snippets. This link contains the entity lifecycle states as well just in case if you need it.

A
Andrew Tobilko

From this forum post

persist() is well defined. It makes a transient instance persistent. However, it doesn't guarantee that the identifier value will be assigned to the persistent instance immediately, the assignment might happen at flush time. The spec doesn't say that, which is the problem I have with persist(). persist() also guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries. This is useful in long-running conversations with an extended Session/persistence context. A method like persist() is required. save() does not guarantee the same, it returns an identifier, and if an INSERT has to be executed to get the identifier (e.g. "identity" generator, not "sequence"), this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context.


to add more from the same post , to whine :"Sadly, 5 years later, this thread still remains the only clear source of information about this subject. The Hibernate documentation, while verbose, is void of all but the most trivial usage information. Why christian's last post is not in the Session javadoc is just another Hibernate documentation mystery."
do you mean the persist() method will make the entity in detached state and the save() in attached state?
i recently used both save and persist in a one-to-many bidirectional mapping. i found out that save does not cascade to the child, i.e., only Parent is saved/inserted in the table. However, persist accomplished the task of saving both Parent and Child in one call. I am using a composite ID not a generated ID.
G
Giorgi Tsiklauri

I have done good research on the save() vs. persist() including running it on my local machine several times. All the previous explanations are confusing and incorrect. I compare save() and persist() methods below after a thorough research.

Save()

Returns generated Id after saving. Its return type is Serializable; Saves the changes to the database outside of the transaction; Assigns the generated id to the entity you are persisting; session.save() for a detached object will create a new row in the table.

Persist()

Does not return generated Id after saving. Its return type is void; Does not save the changes to the database outside of the transaction; Assigns the generated Id to the entity you are persisting; session.persist() for a detached object will throw a PersistentObjectException, as it is not allowed.

All these are tried/tested on Hibernate v4.0.1.


Point 3 for Save() and Persist() are mentioned but they are not actually same. Persist() method save the changes to db outside the transaction also.
when i tested after committing the transaction using persist method value is not saved to DB
So #1 and #5 are the real difference between the two? If You need an id returned or a new row created, use Save()?
How Save() #3 is possible outside transaction
Z
Zeus

I did some mock testing to record the difference between save() and persist().

Sounds like both these methods behaves same when dealing with Transient Entity but differ when dealing with Detached Entity.

For the below example, take EmployeeVehicle as an Entity with PK as vehicleId which is a generated value and vehicleName as one of its properties.

Example 1 : Dealing with Transient Object

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

Result:

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

Note the result is same when you get an already persisted object and save it

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

Repeat the same using persist(entity) and will result the same with new Id ( say 37 , honda ) ;

Example 2 : Dealing with Detached Object

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

Result : You might be expecting the Vehicle with id : 36 obtained in previous session is updated with name as "Toyota" . But what happens is that a new entity is saved in the DB with new Id generated for and Name as "Toyota"

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

Using persist to persist detached entity

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

Result:

Exception being thrown : detached entity passed to persist

So, it is always better to use Persist() rather than Save() as save has to be carefully used when dealing with Transient object .

Important Note : In the above example , the pk of vehicle entity is a generated value , so when using save() to persist a detached entity , hibernate generates a new id to persist . However if this pk is not a generated value than it is result in a exception stating key violated.


C
Community

This question has some good answers about different persistence methods in Hibernate. To answer your question directly, with save() the insert statement is executed immediately regardless of transaction state. It returns the inserted key so you can do something like this:

long newKey = session.save(myObj);

So use save() if you need an identifier assigned to the persistent instance immediately.

With persist(), the insert statement is executed in a transaction, not necessarily immediately. This is preferable in most cases.

Use persist() if you don't need the insert to happen out-of-sequence with the transaction and you don't need the inserted key returned.


y
yeppe

Here are the differences that can help you understand the advantages of persist and save methods:

First difference between save and persist is their return type. The return type of persist method is void while return type of save method is Serializable object.

The persist() method doesn’t guarantee that the identifier value will be assigned to the persistent state immediately, the assignment might happen at flush time.

The persist() method will not execute an insert query if it is called outside of transaction boundaries. While, the save() method returns an identifier so that an insert query is executed immediately to get the identifier, no matter if it are inside or outside of a transaction.

The persist method is called outside of transaction boundaries, it is useful in long-running conversations with an extended Session context. On the other hand save method is not good in a long-running conversation with an extended Session context.

Fifth difference between save and persist method in Hibernate: persist is supported by JPA, while save is only supported by Hibernate.

You can see the full working example from the post Difference between save and persist method in Hibernate


First you say "The persist() method will not execute an insert query if it is called outside of transaction boundaries". Then you say "The persist method is called outside of transaction boundaries, it is useful in long-running conversations with an extended Session context." Aren't they contradictory? I don't understand.
@KumarManish In case of the persist method, an insert query happens at flush time. So it is it is a best practices in long-running conversations
R
Rohit Goyal

save()- As the method name suggests, hibernate save() can be used to save entity to database. We can invoke this method outside a transaction. If we use this without transaction and we have cascading between entities, then only the primary entity gets saved unless we flush the session.

persist()-Hibernate persist is similar to save (with transaction) and it adds the entity object to the persistent context, so any further changes are tracked. If the object properties are changed before the transaction is committed or session is flushed, it will also be saved into database. Also, we can use persist() method only within the boundary of a transaction, so it’s safe and takes care of any cascaded objects. Finally, persist doesn't return anything so we need to use the persisted object to get the generated identifier value.


G
Gaurav Kumar

Basic rule says that :

For Entities with generated identifier :

save() : It returns an entity's identifier immediately in addition to making the object persistent. So an insert query is fired immediately.

persist() : It returns the persistent object. It does not have any compulsion of returning the identifier immediately so it does not guarantee that insert will be fired immediately. It may fire an insert immediately but it is not guaranteed. In some cases, the query may be fired immediately while in others it may be fired at session flush time.

For Entities with assigned identifier :

save(): It returns an entity's identifier immediately. Since the identifier is already assigned to entity before calling save, so insert is not fired immediately. It is fired at session flush time.

persist() : same as save. It also fire insert at flush time.

Suppose we have an entity which uses a generated identifier as follows :

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

Now suppose we have the same entity defined as follows without the id field having generated annotation i.e. ID will be assigned manually.

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

for save() :

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

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

The above cases were true when the save or persist were called from within a transaction.

The other points of difference between save and persist are :

save() can be called outside a transaction. If assigned identifier is used then since id is already available, so no insert query is immediately fired. The query is only fired when the session is flushed. If generated identifier is used , then since id need to generated, insert is immediately fired. But it only saves the primary entity. If the entity has some cascaded entities then those will not be saved in db at this point. They will be saved when the session is flushed. If persist() is outside a transaction then insert is fired only when session is flushed no matter what kind of identifier (generated or assigned) is used. If save is called over a persistent object, then the entity is saved using update query.


D
Donald Duck

Here is the difference:

save: will return the id/identifier when the object is saved to the database. will also save when the object is tried to do the same by opening a new session after it is detached. Persist: will return void when the object is saved to the database. will throw PersistentObjectException when tried to save the detached object through a new session.


Can you please show an example with a snippet. That would be useful.
J
Jabongg

Actually, the difference between hibernate save() and persist() methods depends on generator class we are using. If our generator class is assigned, then there is no difference between save() and persist() methods. Because generator ‘assigned’ means, as a programmer we need to give the primary key value to save in the database right [ Hope you know this generators concept ] In case of other than assigned generator class, suppose if our generator class name is Increment means hibernate itself will assign the primary key id value into the database right [other than assigned generator, hibernate only used to take care the primary key id value remember], so in this case if we call save() or persist() method, then it will insert the record into the database normally. But here, thing is, save() method can return that primary key id value which is generated by hibernate and we can see it by long s = session.save(k); In this same case, persist() will never give any value back to the client, return type void. persist() also guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries. whereas in save(), INSERT happens immediately, no matter if you are inside or outside of a transaction.


What is generator Class here ?
N
Neeraj

It completely answered on basis of "generator" type in ID while storing any entity. If value for generator is "assigned" which means you are supplying the ID. Then it makes no diff in hibernate for save or persist. You can go with any method you want. If value is not "assigned" and you are using save() then you will get ID as return from the save() operation.

Another check is if you are performing the operation outside transaction limit or not. Because persist() belongs to JPA while save() for hibernate. So using persist() outside transaction boundaries will not allow to do so and throw exception related to persistant. while with save() no such restriction and one can go with DB transaction through save() outside the transaction limit.