Controller Logic:
def updateObject() {
Object o = Object.get(params.id as Long)
o.otherObjects.clear()
objectDataService.saveObject(o.id)
OtherObject newObject = new OtherObject;
o.addToOtherObjects(newObject)
objectDataService.saveObject(o.id)
}
ServiceLogic
def saveObject(long profileId) {
o.save(flush:true)
}
what happens
in 90% of the cases this will just work.
problems
ERROR errors.GrailsExceptionResolver - StaleObjectStateException occurred when processing request: [GET] /controller/updateObject - parameters:
stuff[]: data
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.path.Object#1].
Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.path.Object#1]
i have read through related questions and found the merge
call you see above. it solved about 50% of the cases but not all.
StaleObjectStateException:
As already commented out about this exception.
When an invalid version-ed domain object is in the session during a flush (explicit or implicit) the version number is bumped but it is not persisted to the database. Then, when it becomes valid again and saved and flushed, hibernate considers it stale, since the version number does not match the version in the database and it throws a
StaleObjectStateException.
This can be solve like.
- you have to find out version value before doing the update , if it's 1 then you have to update by using program. at particular operation of update .
- By using @version annotation.
About @version:
The version number mechanism for optimistic locking is provided through a @Version annotation.
Example: The @Version annotation
@Entity
public class Flight implements Serializable {
...
@Version
@Column(name="OPTLOCK")
public Integer getVersion() { ... }
}
Here, the version property is mapped to the OPTLOCK column, and the entity manager uses it to detect conflicting updates, and prevent the loss of updates that would be overwritten by a last-commit-wins strategy @version
For more detail on Grails refer below link , it's having Git hub code.
test for GRAILS-8937: HibernateOptimisticLockingFailureException
The StaleObjectStateException can occur naturally on any other project. Every time two concurrent transactions are loading the same entity version and each of those change that entity you end up with the last executing thread failing, due to an optimistic locking collision failure.
In your case there is an extra call, outside of JPA boundaries, that may facilitate this issue:
Object o = PObject.lock(profileId)
Each transaction is thread-bound and it happens inside a Session, so two competing threads will keep two Object references for the same entity id. The optimistic locking goal works effectively without any other explicit locking mechanism.
If you send the modified entity reference to the saveObject
version and you still get this exception, it means you have a high chance for two competing threads to modify the same entities.
In this scenario, a pessimistic lock will yield better results, since it involves waiting as opposed to the optimistic fail-fast approach.
For us a few different approaches finally solved the StaleObjectException from occuring regularly:
object = object.refresh()
refreshing objects after retrieving them solved most of our StaleObjectExceptions. Especially in cases where there was a possibility that someone would have worked on the same object from somewhere else and changed some of its members (most problems arrived with collection members).
Overall Project stability:
wrongly linked resources
we had a 404 on a specific resource file we did not actually need and therefore ignored it for some time. turns out that the missing file would cause the session to be kept open - thus fabricating StaleObjects left and right.
Therefore as a hint to anyone facing more than the usual (some StaleObjects might always occur - see above answers) StaleObjectExceptions: Make sure that all resources are linked correctly and your developer tools (Chrome F12) do not report any missing files.