Reputation: 21405
The hibernate document says:
persist() makes a transient instance persistent. However, it does not guarantee that the identifier value will be assigned to the persistent instance immediately, the assignment might happen at flush time. 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.
save() does guarantee to return an identifier. 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 problematic in a long-running conversation with an extended Session/persistence context.
So I am trying with a small example on how this works. I created an entity called DomesticCat:
@Entity
public class DomesticCat {
@Id
@GeneratedValue
private long id;
private String name;
}
and a small program to test this, once using save()
and another time with persist()
:
private static void saveData() {
Session session = getSession();
DomesticCat cat = new DomesticCat();
cat.setName("My Cat");
//session.save(cat);
session.persist(cat);
}
For this program, hibernate generated same queries for save & persist, in this case it is:
select hibernate_sequence.nextval from dual
Now I added an extra line to my code saying:
session.flush();
Now hibernate generated insert query for both cases i.e save & persist:
insert into CAT (name, id) values (?, ?)
Also when I do session.flush()
, the id
is getting assigned to my cat
object when I use save() and also for persist()
Finally, when I use the transaction then the data is stored in the DB table.
So using this example I can see only single difference between persist vs save, that is save returns the identifier where as persist will not.
Then what exactly the document says, can someone please help me with some examples?
Update:
I am using Oracle as my database.
Now I modified my entity class Id generation strategy to increment as follows:
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
private long id;
But even then I can see that calling session.persist()
is hitting the DB to get the Id value. Here is my program and its output:
private static void saveData() {
Session session = getSession();
DomesticCat cat = new DomesticCat();
cat.setName("My Cat");
System.out.println("before id="+cat.getId());
session.persist(cat);
System.out.println("after id="+cat.getId());
session.flush();
System.out.println("after flush id="+cat.getId());
}
Output:
before id=0
Hibernate: select max(id) from CAT
after id=1
Hibernate: insert into CAT (name, id) values(?, ?)
after flush id=1
As per the output hibernate is hitting the DB to get the ID before I call session.flush() and the case is same for session.save() also. So there is no difference in output if I use Id generation strategy to increment.
Upvotes: 1
Views: 2493
Reputation: 2975
All the information is in the documentation. save()
flushes the entity to the database when you make the call. persist()
actually just marks the entity to be persisted in the upcoming flush. There is a difference and with persist
you have more control on when the actual write to the database takes place.
Upvotes: 2
Reputation: 691735
It's a simple logic problem.
it does not guarantee that the identifier value will be assigned to the persistent instance immediately
is not the same thing as
it guarantees that the identifier value will not be assigned to the persistent instance immediately
The ID generation strategy used for your database is to use a sequence. In that case, Hibernate asks the sequence for the next ID when calling persist(). If the ID generation strategy for your database was to use an auto-increment column, the ID would only be assigned to the entity only when the entity is inserted to the database, at flush time.
Upvotes: 1