Q:

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?

A:

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.

A:

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.

A:

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.

