What's the difference between session.persist() and session.save() in Hibernate?
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 withpersist()
.
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.
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 aPersistentObjectException
, as it is not allowed.
All these are tried/tested on Hibernate v4.0.1
.
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.