How to fix StaleObjectStateException with JPA and Hibernate

Sebastian Flückiger picture Sebastian Flückiger · Aug 27, 2014 · Viewed 19.4k times · Source

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.

Answer

Rudra picture Rudra · Sep 3, 2014

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.

  1. 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 .
  2. 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