Hibernate saveOrUpdate behavior
When you use .saveOrUpdate()
Hibernate will check if the object is transient (it has no identifier property) and if so it will make it persistent by generating it the identifier and assigning it to session. If the object has an identifier already it will perform .update()
.
From the documentation:
saveOrUpdate() does the following:
- if the object is already persistent in this session, do nothing
- if another object associated with the session has the same identifier, throw an exception
- if the object has no identifier property, save() it
- if the object's identifier has the value assigned to a newly instantiated object, save() it
- if the object is versioned by a "version" or "timestamp", and the version property value is the same value assigned to a newly instantiated object, save() it otherwise update() the object
Perhaps it is helpful to quote the Hibernate bible (Java Persistence with Hibernate, 2nd ed., page 528):
More experienced Hibernate users use
saveOrUpdate()
exclusively; it's much easier to let Hibernate decide what is new and what is old, especially in a more complex network of objects with mixed state. The only (not really serious) disadvantage of exclusivesaveOrUpdate()
is that it sometimes can't guess whether an instance is old or new without firing aSELECT
at the database - for example, when a class is mapped with a natural composite key and no version or timestamp property.How does Hibernate detect which instances are old and which are new? A range of options is available. Hibernate assumes that an instance is an unsaved transient instance if:
- The identifier property is
null
.- The version or timestamp property (if it exists) is
null
.- A new instance of the same persistent class, created by Hibernate internally, has the same database identifier values as the given instance.
- You supply an
unsaved-value
in the mapping document for the class, and the value of the identifier property matches. Theunsaved-value
attribute is also available for version and timestamp mapping elements.- Entity data with the same identifier value isn't in the second-level cache.
- You supply an implementation or
org.hibernate.Interceptor
and returnBoolean.TRUE
fromInterceptor.isUnsaved()
after checking the instance in your code.
As stated here, saveOrUpdate
either saves a transient instance by generating a new identifier or updates/reattaches the detached instances associated with its current identifier. More specifically it does:
- if the object is already persistent in this session, do nothing
- if another object associated with the session has the same identifier, throw an exception
- if the object has no identifier property,
save()
it - if the object's identifier has the value assigned to a newly instantiated object, save() it
- if the object is versioned by a
<version>
or<timestamp>
, and the version property value is - the same value assigned to a newly instantiated object,
save()
it - otherwise
update()
the object